すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud Model Studio:視覚的推論 (QVQ)

最終更新日:Jul 12, 2025

QVQ モデルは強力な視覚的推論機能を備えています。最初に思考プロセスを出力し、次に応答内容を出力します。現在、QVQ はストリーミング出力のみをサポートしています

対応モデル

QVQ は、視覚的入力と連鎖的思考出力をサポートする視覚的推論モデルです。数学、プログラミング、視覚分析、創作、および一般的なタスクにおいて、より強力な機能を発揮します。

名前

バージョン

コンテキストウィンドウ

最大入力

最大 CoT

最大応答

入力価格

出力価格

無料枠

(注)

(トークン)

(百万トークン)

qvq-max

qvq-max-2025-03-25 と同じパフォーマンス

安定版

131,072

106,496

画像あたり最大 16,384

16,384

8,192

$1.2

$4.8

それぞれ 100 万トークン

アクティベーション後 180 日間有効

qvq-max-latest

常に最新のスナップショットと同じパフォーマンス

最新版

qvq-max-2025-03-25

qvq-max-0325 とも呼ばれます

スナップショット

画像と動画のトークンを計算する

画像

28 × 28 ピクセルごとに 1 トークンに相当し、画像は少なくとも 4 トークンが必要です。次のコードを使用して、画像のトークンを推定できます。

import math
# Pillow ライブラリをインストールするには、次のコマンドを使用します。pip install Pillow
from PIL import Image

def token_calculate(image_path):
    # 指定された PNG 画像ファイルを開きます
    image = Image.open(image_path)

    # 画像の元の寸法を取得します
    height = image.height
    width = image.width
    
    # 高さを 28 の倍数に調整します
    h_bar = round(height / 28) * 28
    # 幅を 28 の倍数に調整します
    w_bar = round(width / 28) * 28
    
    # 画像の最小トークン制限:4 トークン
    min_pixels = 28 * 28 * 4
    # 画像の最大トークン制限:1280 トークン
    max_pixels = 1280 * 28 * 28
        
    # 画像をスケーリングして、ピクセル総数が [min_pixels、max_pixels] の範囲内にあることを確認します
    if h_bar * w_bar > max_pixels:
        # スケーリング係数 beta を計算して、スケーリングされた画像のピクセル総数が max_pixels を超えないようにします
        beta = math.sqrt((height * width) / max_pixels)
        # 調整された高さを再計算し、28 の倍数であることを確認します
        h_bar = math.floor(height / beta / 28) * 28
        # 調整された幅を再計算し、28 の倍数であることを確認します
        w_bar = math.floor(width / beta / 28) * 28
    elif h_bar * w_bar < min_pixels:
        # スケーリング係数 beta を計算して、スケーリングされた画像のピクセル総数が min_pixels 以上になるようにします
        beta = math.sqrt(min_pixels / (height * width))
        # 調整された高さを再計算し、28 の倍数であることを確認します
        h_bar = math.ceil(height * beta / 28) * 28
        # 調整された幅を再計算し、28 の倍数であることを確認します
        w_bar = math.ceil(width * beta / 28) * 28
    return h_bar, w_bar

# test.png をローカル画像のパスに置き換えます
h_bar, w_bar = token_calculate("test.png")
print(f"スケーリングされた画像の寸法:高さ {h_bar}、幅 {w_bar}")

# 画像のトークン数を計算します:ピクセル総数を 28 * 28 で割ります
token = int((h_bar * w_bar) / (28 * 28))

# システムは自動的に視覚マーカー <|vision_bos|> と <|vision_eos|> を追加します(それぞれ 1 トークン)
print(f"画像のトークン数は {token + 2}")
// sharp をインストールするには、次のコマンドを使用します。npm install sharp
import sharp from 'sharp';
import fs from 'fs';

async function tokenCalculate(imagePath) {
    // 指定された PNG 画像ファイルを開きます
    const image = sharp(imagePath);
    const metadata = await image.metadata();

    // 画像の元の寸法を取得します
    const height = metadata.height;
    const width = metadata.width;

    // 高さを 28 の倍数に調整します
    let hBar = Math.round(height / 28) * 28;
    // 幅を 28 の倍数に調整します
    let wBar = Math.round(width / 28) * 28;

    // 画像の最小トークン制限:4 トークン
    const minPixels = 28 * 28 * 4;
    // 画像の最大トークン制限:1280 トークン
    const maxPixels = 1280 * 28 * 28;

    // 画像をスケーリングして、ピクセル総数が [minPixels、maxPixels] の範囲内にあることを確認します
    if (hBar * wBar > maxPixels) {
        // スケーリング係数 beta を計算して、スケーリングされた画像のピクセル総数が maxPixels を超えないようにします
        const beta = Math.sqrt((height * width) / maxPixels);
        // 調整された高さを再計算し、28 の倍数であることを確認します
        hBar = Math.floor(height / beta / 28) * 28;
        // 調整された幅を再計算し、28 の倍数であることを確認します
        wBar = Math.floor(width / beta / 28) * 28;
    } else if (hBar * wBar < minPixels) {
        // スケーリング係数 beta を計算して、スケーリングされた画像のピクセル総数が minPixels 以上になるようにします
        const beta = Math.sqrt(minPixels / (height * width));
        // 調整された高さを再計算し、28 の倍数であることを確認します
        hBar = Math.ceil(height * beta / 28) * 28;
        // 調整された幅を再計算し、28 の倍数であることを確認します
        wBar = Math.ceil(width * beta / 28) * 28;
    }

    return { hBar, wBar };
}

// test.png をローカル画像のパスに置き換えます
const imagePath = 'test.png';
tokenCalculate(imagePath).then(({ hBar, wBar }) => {
    console.log(`スケーリングされた画像の寸法:高さ ${hBar}、幅 ${wBar}`);

    // 画像のトークン数を計算します:ピクセル総数を 28 * 28 で割ります
    const token = Math.floor((hBar * wBar) / (28 * 28));

    // システムは自動的に視覚マーカー <|vision_bos|> と <|vision_eos|> を追加します(それぞれ 1 トークン)
    console.log(`画像のトークン数は ${token + 2}`);
}).catch(err => {
    console.error('画像の処理中にエラーが発生しました:', err);
});
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class Main {

    // リサイズされた寸法を格納するためのカスタムクラス
    public static class ResizedSize {
        public final int height;
        public final int width;

        public ResizedSize(int height, int width) {
            this.height = height;
            this.width = width;
        }
    }

    public static ResizedSize smartResize(String imagePath) throws IOException {
        // 1. 画像を読み込みます
        BufferedImage image = ImageIO.read(new File(imagePath));
        if (image == null) {
            throw new IOException("画像ファイルを読み込めません:" + imagePath);
        }

        int originalHeight = image.getHeight();
        int originalWidth = image.getWidth();

        final int minPixels = 28 * 28 * 4;
        final int maxPixels = 1280 * 28 * 28;
        // 2. 最初の調整を 28 の倍数にします
        int hBar = (int) (Math.round(originalHeight / 28.0) * 28);
        int wBar = (int) (Math.round(originalWidth / 28.0) * 28);
        int currentPixels = hBar * wBar;

        // 3. 条件に基づいて寸法を調整します
        if (currentPixels > maxPixels) {
            // 現在のピクセルが最大値を超えているため、縮小する必要があります
            double beta = Math.sqrt(
                    (originalHeight * (double) originalWidth) / maxPixels
            );
            double scaledHeight = originalHeight / beta;
            double scaledWidth = originalWidth / beta;

            hBar = (int) (Math.floor(scaledHeight / 28) * 28);
            wBar = (int) (Math.floor(scaledWidth / 28) * 28);
        } else if (currentPixels < minPixels) {
            // 現在のピクセルが最小値を下回っているため、拡大する必要があります
            double beta = Math.sqrt(
                    (double) minPixels / (originalHeight * originalWidth)
            );
            double scaledHeight = originalHeight * beta;
            double scaledWidth = originalWidth * beta;

            hBar = (int) (Math.ceil(scaledHeight / 28) * 28);
            wBar = (int) (Math.ceil(scaledWidth / 28) * 28);
        }

        return new ResizedSize(hBar, wBar);
    }

    public static void main(String[] args) {
        try {
            ResizedSize size = smartResize(
                    // xxx/test.png を画像パスに置き換えます
                    "xxx/test.png"
            );

            System.out.printf("スケーリングされた画像の寸法:高さ %d、幅 %d%n", size.height, size.width);

            // トークンを計算します(ピクセル総数 / 28 × 28 + 2)
            int token = (size.height * size.width) / (28 * 28) + 2;
            System.out.printf("画像のトークン数:%d%n", token);

        } catch (IOException e) {
            System.err.println("エラー:" + e.getMessage());
            e.printStackTrace();
        }
    }
}

動画

次のコードを使用して、動画のトークンを推定できます。

# 使用前にインストールします。pip install opencv-python
import math
import os
import logging
import cv2

logger = logging.getLogger(__name__)

FRAME_FACTOR = 2
IMAGE_FACTOR = 28
# 動画フレームの縦横比
MAX_RATIO = 200

# 動画フレームの最小トークン制限
VIDEO_MIN_PIXELS = 128 * 28 * 28
# 動画フレームの最大トークン制限
VIDEO_MAX_PIXELS = 768 * 28 * 28

# ユーザーが FPS パラメーターを渡さない場合は、デフォルト値を使用します
FPS = 2.0
# 抽出する最小フレーム数
FPS_MIN_FRAMES = 4
# 抽出する最大フレーム数。qwen2.5-vl モデルを使用する場合は、FPS_MAX_FRAMES を 512 に設定します。他のモデルの場合は、80 に設定します
FPS_MAX_FRAMES = 512

# 動画入力の最大ピクセル値
# qwen2.5-vl モデルを使用する場合は、VIDEO_TOTAL_PIXELS を 65536 * 28 * 28 に設定します。他のモデルの場合は、24576 * 28 * 28 に設定します
VIDEO_TOTAL_PIXELS = int(float(os.environ.get('VIDEO_MAX_PIXELS', 65536 * 28 * 28)))

def round_by_factor(number: int, factor: int) -> int:
    """'factor' で割り切れる 'number' に最も近い整数を返します。"""
    return round(number / factor) * factor

def ceil_by_factor(number: int, factor: int) -> int:
    """'factor' で割り切れる 'number' 以上の最小の整数を返します。"""
    return math.ceil(number / factor) * factor

def floor_by_factor(number: int, factor: int) -> int:
    """'factor' で割り切れる 'number' 以下の最大の整数を返します。"""
    return math.floor(number / factor) * factor

def smart_nframes(ele,total_frames,video_fps):
    """抽出する動画フレームの数を計算します。

    Args:
        ele (dict): 動画構成を含む辞書
            - fps: fps は、モデルによって抽出される入力フレームの数を制御するために使用されます。
        total_frames (int): 元の動画の合計フレーム数。
        video_fps (int | float): 動画の元のフレームレート

    Raises:
        nframes は [FRAME_FACTOR、total_frames] の範囲内である必要があります。そうでない場合は、エラーがスローされます

    Returns:
        モデル入力の動画フレームの数。
    """
    assert not ("fps" in ele and "nframes" in ele), "「fps」または「nframes」のいずれかのみを受け入れます"
    fps = ele.get("fps", FPS)
    min_frames = ceil_by_factor(ele.get("min_frames", FPS_MIN_FRAMES), FRAME_FACTOR)
    max_frames = floor_by_factor(ele.get("max_frames", min(FPS_MAX_FRAMES, total_frames)), FRAME_FACTOR)
    duration = total_frames / video_fps if video_fps != 0 else 0
    if duration-int(duration) > (1/fps):
        total_frames = math.ceil(duration * video_fps)
    else:
        total_frames = math.ceil(int(duration) * video_fps)
    nframes = total_frames / video_fps * fps
    if nframes > total_frames:
        logger.warning(f"smart_nframes: nframes[{nframes}] > total_frames[{total_frames}]")
    nframes = int(min(min(max(nframes, min_frames), max_frames), total_frames))
    if not (FRAME_FACTOR <= nframes and nframes <= total_frames):
        raise ValueError(f"nframes は [{FRAME_FACTOR}、{total_frames}] の間隔である必要がありますが、{nframes} が取得されました。")

    return nframes

def get_video(video_path):
    # 動画情報を取得します
    cap = cv2.VideoCapture(video_path)

    frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    # 動画の高さを取得します
    frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    video_fps = cap.get(cv2.CAP_PROP_FPS)
    return frame_height, frame_width, total_frames, video_fps

def smart_resize(ele, path, factor=IMAGE_FACTOR):
    # 元の動画の幅と高さを取得します
    height, width, total_frames, video_fps = get_video(path)
    # 動画フレームの最小トークン制限
    min_pixels = VIDEO_MIN_PIXELS
    total_pixels = VIDEO_TOTAL_PIXELS
    # 抽出された動画フレームの数
    nframes = smart_nframes(ele, total_frames, video_fps)
    max_pixels = max(min(VIDEO_MAX_PIXELS, total_pixels / nframes * FRAME_FACTOR), int(min_pixels * 1.05))

    # 動画の縦横比は 200:1 または 1:200 を超えてはなりません
    if max(height, width) / min(height, width) > MAX_RATIO:
        raise ValueError(
            f"絶対縦横比は {MAX_RATIO} より小さくなければなりませんが、{max(height, width) / min(height, width)} が取得されました"
        )

    h_bar = max(factor, round_by_factor(height, factor))
    w_bar = max(factor, round_by_factor(width, factor))
    if h_bar * w_bar > max_pixels:
        beta = math.sqrt((height * width) / max_pixels)
        h_bar = floor_by_factor(height / beta, factor)
        w_bar = floor_by_factor(width / beta, factor)
    elif h_bar * w_bar < min_pixels:
        beta = math.sqrt(min_pixels / (height * width))
        h_bar = ceil_by_factor(height * beta, factor)
        w_bar = ceil_by_factor(width * beta, factor)
    return h_bar, w_bar
    

def token_calculate(video_path, fps):
    # 動画パスと fps 抽出パラメーターを渡します
    messages = [{"content": [{"video": video_path, "fps": fps}]}]
    vision_infos = extract_vision_info(messages)[0]

    resized_height, resized_width = smart_resize(vision_infos, video_path)

    height, width, total_frames, video_fps = get_video(video_path)
    num_frames = smart_nframes(vision_infos, total_frames, video_fps)
    print(f"元の動画サイズ:{height}*{width}、モデル入力のサイズ:{resized_height}*{resized_width}、動画の合計フレーム数:{total_frames}、fps が {fps} の場合、抽出された合計フレーム数:{num_frames}", end=", ")
    video_token = int(math.ceil(num_frames / 2) * resized_height / 28 * resized_width / 28)
    video_token += 2  # システムは自動的に視覚マーカー <|vision_bos|> と <|vision_eos|> を追加します(それぞれ 1 トークンとしてカウントされます)
    return video_token

def extract_vision_info(conversations):
    vision_infos = []
    if isinstance(conversations[0], dict):
        conversations = [conversations]
    for conversation in conversations:
        for message in conversation:
            if isinstance(message["content"], list):
                for ele in message["content"]:
                    if (
                        "image" in ele
                        or "image_url" in ele
                        or "video" in ele
                        or ele.get("type", "") in ("image", "image_url", "video")
                    ):
                        vision_infos.append(ele)
    return vision_infos


video_token = token_calculate("xxx/test.mp4", 1)
print("動画トークン:", video_token)
// 使用前にインストールします。npm i node-ffprobe
import ffprobeInstaller from '@ffprobe-installer/ffprobe';
import ffprobe from 'node-ffprobe';
import probe from "node-ffprobe";
// ffprobe パスを設定します(グローバル構成)
ffprobe.FFPROBE_PATH = ffprobeInstaller.path;

// 動画情報を取得します
async function getVideoInfo(videoPath) {
  try {
    const probeData = await probe(videoPath);
    const videoStream = probeData.streams.find(
      stream => stream.codec_type === 'video'
    );

    if (!videoStream) {
      throw new Error('動画に動画ストリームが見つかりません');
    }

    const width = videoStream.width;
    const height = videoStream.height;
    const totalFrames = videoStream.nb_frames;
    const [numerator, denominator] = videoStream.avg_frame_rate.split('/');
    const frameRate = parseFloat(numerator / denominator);

    return {
      width,
      height,
      totalFrames,
      frameRate
    };
  } catch (error) {
    console.error('動画情報の取得に失敗しました:', error);
    throw error;
  }
}

// 構成パラメーター
const FRAME_FACTOR = 2; 
const IMAGE_FACTOR = 28;
const MAX_RATIO = 200;
// 動画フレームの最小トークン制限
const VIDEO_MIN_PIXELS = 128 * 28 * 28; 
// 動画フレームの最大トークン制限
const VIDEO_MAX_PIXELS = 768 * 28 * 28; 
const FPS = 2.0; // ユーザーが FPS パラメーターを渡さない場合は、デフォルト値を使用します
// 抽出する最小フレーム数
const FPS_MIN_FRAMES = 4;
// 抽出する最大フレーム数。qwen2.5-vl モデルを使用する場合は、FPS_MAX_FRAMES を 512 に設定します。他のモデルの場合は、80 に設定します
const FPS_MAX_FRAMES = 512; 
// 動画入力の最大ピクセル値
// qwen2.5-vl モデルを使用する場合は、VIDEO_TOTAL_PIXELS を 65536 * 28 * 28 に設定します。他のモデルの場合は、24576 * 28 * 28 に設定します
const VIDEO_TOTAL_PIXELS = parseInt(process.env.VIDEO_MAX_PIXELS) || 65536 * 28 * 28;

// 数学ユーティリティ関数
function roundByFactor(number, factor) {
    return Math.round(number / factor) * factor;
}

function ceilByFactor(number, factor) {
    return Math.ceil(number / factor) * factor;
}

function floorByFactor(number, factor) {
    return Math.floor(number / factor) * factor;
}

// 抽出するフレームの数を計算します
function smartNFrames(ele, totalFrames, frameRate) {
    const fps = ele.fps || FPS;
    const minFrames = ceilByFactor(ele.min_frames || FPS_MIN_FRAMES, FRAME_FACTOR);
    const maxFrames = floorByFactor(
        ele.max_frames || Math.min(FPS_MAX_FRAMES, totalFrames),
        FRAME_FACTOR
    );
    const duration = frameRate !== 0 ? parseFloat(totalFrames / frameRate) : 0;

    let totalFramesAdjusted = duration % 1 > (1 / fps)
        ? Math.ceil(duration * frameRate)
        : Math.ceil(Math.floor(parseInt(duration)) * frameRate);

    const nframes = (totalFramesAdjusted / frameRate) * fps;
    const finalNFrames = parseInt(Math.min(
        Math.max(nframes, minFrames),
        Math.min(maxFrames, totalFramesAdjusted)
    ));

    if (finalNFrames < FRAME_FACTOR || finalNFrames > totalFramesAdjusted) {
        throw new Error(
            `nframes は ${FRAME_FACTOR} から ${totalFramesAdjusted} の間である必要がありますが、${finalNFrames} が取得されました`
        );
    }
    return finalNFrames;
}

// 解像度をスマートに調整します
async function smartResize(ele, videoPath) {
    const { height, width, totalFrames, frameRate } = await getVideoInfo(videoPath);
    const minPixels = VIDEO_MIN_PIXELS;
    const nframes = smartNFrames(ele, totalFrames, frameRate);
    const maxPixels = Math.max(
        Math.min(VIDEO_MAX_PIXELS, VIDEO_TOTAL_PIXELS / nframes * FRAME_FACTOR),
        Math.floor(minPixels * 1.05)
    );

    // 縦横比を確認します
    const ratio = Math.max(height, width) / Math.min(height, width);
    if (ratio > MAX_RATIO) {
        throw new Error(`縦横比 ${ratio} が ${MAX_RATIO} を超えています`);
    }

    let hBar = Math.max(IMAGE_FACTOR, roundByFactor(height, IMAGE_FACTOR));
    let wBar = Math.max(IMAGE_FACTOR, roundByFactor(width, IMAGE_FACTOR));

    if (hBar * wBar > maxPixels) {
        const beta = Math.sqrt((height * width) / maxPixels);
        hBar = floorByFactor(height / beta, IMAGE_FACTOR);
        wBar = floorByFactor(width / beta, IMAGE_FACTOR);
    } else if (hBar * wBar < minPixels) {
        const beta = Math.sqrt(minPixels / (height * width));
        hBar = ceilByFactor(height * beta, IMAGE_FACTOR);
        wBar = ceilByFactor(width * beta, IMAGE_FACTOR);
    }

    return { hBar, wBar };
}

// トークン数を計算します
async function tokenCalculate(videoPath, fps) {
    const messages = [{ content: [{ video: videoPath, fps }] }];
    const visionInfos = extractVisionInfo(messages);

    const { hBar, wBar } = await smartResize(visionInfos[0], videoPath);
    const { height, width, totalFrames, frameRate } = await getVideoInfo(videoPath);
    const numFrames = smartNFrames(visionInfos[0], totalFrames, frameRate);

    console.log(
        `元の動画サイズ:${height}*${width}、モデル入力のサイズ:${hBar}*${wBar}、動画の合計フレーム数:${totalFrames}、fps が ${fps} の場合、抽出された合計フレーム数:${numFrames}`
    );

    const videoToken = Math.ceil(numFrames / 2) * Math.floor(hBar / 28) * Math.floor(wBar / 28) + 2;
    return videoToken;
}

// 視覚情報を抽出します
function extractVisionInfo(conversations) {
    const visionInfos = [];
    if (!Array.isArray(conversations)) {
        conversations = [conversations];
    }
    conversations.forEach(conversation => {
        if (!Array.isArray(conversation)) {
            conversation = [conversation];
        }
        conversation.forEach(message => {
            if (Array.isArray(message.content)) {
                message.content.forEach(ele => {
                    if (ele.image || ele.image_url || ele.video || ['image', 'image_url', 'video'].includes(ele.type)) {
                        visionInfos.push(ele);
                    }
                });
            }
        });
    });
    return visionInfos;
}

// 使用例
(async () => {
    try {
        const videoPath = "xxx/test.mp4"; // ローカルパスに置き換えます
        const videoToken = await tokenCalculate(videoPath, 1);
        console.log('動画トークン:', videoToken);
    } catch (error) {
        console.error('エラー:', error.message);
    }
})();
同時実行レート制限については、レート制限 を参照してください。

始めよう

前提条件:API キーを取得 し、環境変数として構成 する必要があります。 SDK を使用するには、OpenAI または DashScope SDK をインストール する必要があります。 Java 用の DashScope SDK は、バージョン 2.19.0 以降である必要があります。

重要
  • 推論時間が長いため、現在 QVQ はストリーミング出力のみをサポートしています

  • QVQ では思考を無効にすることはできません。

  • QVQ はシステムメッセージをサポートしていません。

  • DashScope メソッドの場合:

    • incremental_output はデフォルトで true であり、false にすることはできません。

    • result_format はデフォルトで "message" であり、"text" にすることはできません。

次のサンプルコードは、理解のために画像 URL を使用しています。

入力画像の制限 セクションを確認してください。ローカル画像を使用するには、ローカルファイルの使用 を参照してください。

OpenAI

Python

サンプルコード

from openai import OpenAI
import os

# OpenAI クライアントを初期化します
client = OpenAI(
    # 環境変数が構成されていない場合は、Model Studio API キーに置き換えます。api_key="sk-xxx"
    api_key = os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
)

reasoning_content = ""  # 完全な思考プロセスを定義します
answer_content = ""     # 完全な応答を定義します
is_answering = False   # 思考プロセスが終了し、応答が開始されたかどうかを判断します

# チャット補完リクエストを作成します
completion = client.chat.completions.create(
    model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じて他のモデル名に置き換えることができます
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"
                    },
                },
                {"type": "text", "text": "この問題を解く方法は?"},
            ],
        },
    ],
    stream=True,
    # 最後のチャンクでトークンの使用状況を返すには、次のコメントを外します
    # stream_options={
    #     "include_usage": True
    # }
)

print("\n" + "=" * 20 + "推論プロセス" + "=" * 20 + "\n")

for chunk in completion:
    # chunk.choices が空の場合は、使用状況を出力します
    if not chunk.choices:
        print("\n使用状況:")
        print(chunk.usage)
    else:
        delta = chunk.choices[0].delta
        # 思考プロセスを出力します
        if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
            print(delta.reasoning_content, end='', flush=True)
            reasoning_content += delta.reasoning_content
        else:
            # 応答を開始します
            if delta.content != "" and is_answering is False:
                print("\n" + "=" * 20 + "完全な応答" + "=" * 20 + "\n")
                is_answering = True
            # 応答プロセスを出力します
            print(delta.content, end='', flush=True)
            answer_content += delta.content

# print("=" * 20 + "完全な推論プロセス" + "=" * 20 + "\n")
# print(reasoning_content)
# print("=" * 20 + "完全な応答" + "=" * 20 + "\n")
# print(answer_content)

推論プロセスと完全な応答を表示するには、クリックしてください

====================推論プロセス====================

さて、見てみましょう。これらの 2 つの図形の表面積と体積を求める必要があります。最初の図形は直方体で、2 番目の図形は立方体です。うーん、そうです。最初の図形から始めましょう。

直方体の表面積の公式は 2lw + 2lh + 2wh です。寸法は 4 cm、3 cm、2 cm です。それらを代入すると、2*(4*3) + 2*(4*2) + 2*(3*2) になります。各部分について計算してみましょう。4*3 は 12 で、2 倍すると 24 です。次に、4*2 は 8 で、2 倍すると 16 です。次に、3*2 は 6 で、2 倍すると 12 です。それらを合計すると、24 + 16 は 40 で、12 を加えると 52 になります。したがって、表面積は 52 cm² になります。体積は、長さ * 幅 * 高さなので、4*3*2 です。これは 12*2=24 cm³ です。大丈夫、合っているようです。

次に、立方体です。すべての辺は 3 cm です。立方体の表面積は、1 つの面の面積の 6 倍です。各面は 3*3=9 cm² なので、6*9=54 cm² です。体積は辺の 3 乗なので、3*3*3=27 cm³ です。もう一度確認してみましょう。はい、立方体はすべての辺が等しいので、公式は理にかなっています。これで全部だと思います。ちょっと待ってください、数字を間違えていませんでしたか?最初の図形をもう一度確認してみましょう。直方体の寸法は 4、3、2 です。したがって、表面積の計算は正しかったです。体積は 4*3*2=24 です。立方体は簡単です。わかりました、これで全部だと思います。

====================完全な応答====================

問題を解くために、それぞれの公式を使用して、直方体と立方体の表面積と体積を計算します。

### 直方体 (4 cm × 3 cm × 2 cm):
- **表面積**:  
  \(2(lw + lh + wh) = 2(4 \times 3 + 4 \times 2 + 3 \times 2) = 2(12 + 8 + 6) = 2 \times 26 = 52 \, \text{cm}^2\)。  
- **体積**:  
  \(l \times w \times h = 4 \times 3 \times 2 = 24 \, \text{cm}^3\)。

### 立方体 (3 cm × 3 cm × 3 cm):
- **表面積**:  
  \(6s^2 = 6 \times 3^2 = 6 \times 9 = 54 \, \text{cm}^2\)。  
- **体積**:  
  \(s^3 = 3^3 = 27 \, \text{cm}^3\)。

**最終的な回答**:
1. 直方体:表面積 = 52 cm²、体積 = 24 cm³。
2. 立方体:表面積 = 54 cm²、体積 = 27 cm³。

Node.js

サンプルコード

import OpenAI from "openai";
import process from 'process';

// openai クライアントを初期化します
const openai = new OpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY, // 環境変数から読み取ります
    baseURL: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1'
});

let reasoningContent = '';
let answerContent = '';
let isAnswering = false;

let messages = [
    {
        role: "user",
    content: [
        { type: "image_url", image_url: { "url": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg" } },
        { type: "text", text: "この問題を解いてください" },
    ]
}]

async function main() {
    try {
        const stream = await openai.chat.completions.create({
            model: 'qvq-max',
            messages: messages,
            stream: true
        });

        console.log('\n' + '='.repeat(20) + '推論プロセス' + '='.repeat(20) + '\n');

        for await (const chunk of stream) {
            if (!chunk.choices?.length) {
                console.log('\n使用状況:');
                console.log(chunk.usage);
                continue;
            }

            const delta = chunk.choices[0].delta;

            // 思考プロセスを処理します
            if (delta.reasoning_content) {
                process.stdout.write(delta.reasoning_content);
                reasoningContent += delta.reasoning_content;
            }
            // 正式な応答を処理します
            else if (delta.content) {
                if (!isAnswering) {
                    console.log('\n' + '='.repeat(20) + '完全な応答' + '='.repeat(20) + '\n');
                    isAnswering = true;
                }
                process.stdout.write(delta.content);
                answerContent += delta.content;
            }
        }
    } catch (error) {
        console.error('エラー:', error);
    }
}

main();

推論プロセスと完全な応答を表示するには、クリックしてください

====================推論プロセス====================

さて、見てみましょう。これらの 2 つの図形の表面積と体積を求める必要があります。最初の図形は直方体で、2 番目の図形は立方体です。うーん、そうです。最初の図形から始めましょう。

直方体の表面積の公式は 2lw + 2lh + 2wh です。寸法は、長さ 4 cm、幅 3 cm、高さ 2 cm として指定されています。それらを代入すると、2*(4*3) + 2*(4*2) + 2*(3*2) になります。各部分について計算してみましょう。4*3 は 12 で、2 倍すると 24 です。次に、4*2 は 8 で、2 倍すると 16 です。次に、3*2 は 6 で、2 倍すると 12 です。それらを合計すると、24 + 16 は 40 で、12 を加えると 52 になります。したがって、表面積は 52 cm² になります。体積は、長さ * 幅 * 高さなので、4*3*2 です。これは 12*2=24 cm³ です。大丈夫、合っているようです。

次に、2 番目の図形は辺の長さが 3 cm の立方体です。立方体の表面積は、1 つの面の面積の 6 倍です。各面は 3x3 なので、9 cm² です。したがって、6*9=54 cm² です。体積は辺の長さの 3 乗なので、3*3*3=27 cm³ です。もう一度確認してみましょう。はい、立方体の公式は簡単です。

ちょっと待ってください、数字を間違えていませんでしたか?直方体の寸法は 4、3、2 です。したがって、長さ、幅、高さです。表面積の計算は 2*(4*3 + 4*2 + 3*2) でした。これは 2*(12 + 8 + 6) = 2*26=52 です。正しいです。体積は 4*3*2=24 です。立方体はすべての辺が等しいので、3^3=27 です。表面積は 6*3^2=54 です。はい、そうです。これで全部だと思います。

====================完全な応答====================

問題を解くために、それぞれの公式を使用して、直方体と立方体の表面積と体積を計算します。

**1. 直方体 (長さ = 4 cm、幅 = 3 cm、高さ = 2 cm):**
- **表面積**:  
  \[
  2(lw + lh + wh) = 2(4 \times 3 + 4 \times 2 + 3 \times 2) = 2(12 + 8 + 6) = 2 \times 26 = 52 \, \text{cm}^2
  \]
- **体積**:  
  \[
  l \times w \times h = 4 \times 3 \times 2 = 24 \, \text{cm}^3
  \]

**2. 立方体 (辺の長さ = 3 cm):**
- **表面積**:  
  \[
  6a^2 = 6 \times 3^2 = 6 \times 9 = 54 \, \text{cm}^2
  \]
- **体積**:  
  \[
  a^3 = 3^3 = 27 \, \text{cm}^3
  \]

**最終的な回答**:
1. 直方体:表面積 = 52 cm²、体積 = 24 cm³
2. 立方体:表面積 = 54 cm²、体積 = 27 cm³

HTTP

サンプルコード

curl --location 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions' \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
    "model": "qvq-max",
    "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "image_url",
          "image_url": {
            "url": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"
          }
        },
        {
          "type": "text",
          "text": "この問題を解いてください"
        }
      ]
    }
  ],
    "stream":true,
    "stream_options":{"include_usage":true}
}'

推論プロセスと完全な応答を表示するには、クリックしてください

data: {"choices":[{"delta":{"content":null,"role":"assistant","reasoning_content":""},"index":0,"logprobs":null,"finish_reason":null}],"object":"chat.completion.chunk","usage":null,"created":1742983020,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-ab4f3963-2c2a-9291-bda2-65d5b325f435"}

data: {"choices":[{"finish_reason":null,"delta":{"content":null,"reasoning_content":"さて"},"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1742983020,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-ab4f3963-2c2a-9291-bda2-65d5b325f435"}

data: {"choices":[{"delta":{"content":null,"reasoning_content":"、"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1742983020,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-ab4f3963-2c2a-9291-bda2-65d5b325f435"}

data: {"choices":[{"delta":{"content":null,"reasoning_content":"私は"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1742983020,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-ab4f3963-2c2a-9291-bda2-65d5b325f435"}

data: {"choices":[{"delta":{"content":null,"reasoning_content":"この"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1742983020,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-ab4f3963-2c2a-9291-bda2-65d5b325f435"}

data: {"choices":[{"delta":{"content":null,"reasoning_content":"問題を"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1742983020,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-ab4f3963-2c2a-9291-bda2-65d5b325f435"}
.....
data: {"choices":[{"delta":{"content":"cm"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1742983095,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-23d30959-42b4-9f24-b7ab-1bb0f72ce265"}

data: {"choices":[{"delta":{"content":"³"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1742983095,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-23d30959-42b4-9f24-b7ab-1bb0f72ce265"}

data: {"choices":[{"finish_reason":"stop","delta":{"content":"","reasoning_content":null},"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1742983095,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-23d30959-42b4-9f24-b7ab-1bb0f72ce265"}

data: {"choices":[],"object":"chat.completion.chunk","usage":{"prompt_tokens":544,"completion_tokens":590,"total_tokens":1134,"completion_tokens_details":{"text_tokens":590},"prompt_tokens_details":{"text_tokens":24,"image_tokens":520}},"created":1742983095,"system_fingerprint":null,"model":"qvq-max","id":"chatcmpl-23d30959-42b4-9f24-b7ab-1bb0f72ce265"}

data: [DONE]

DashScope

Python

サンプルコード

import os
import dashscope
from dashscope import MultiModalConversation

dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'

messages = [
    {
        "role": "user",
        "content": [
            {"image": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"},
            {"text": "この問題を解いてください。"}
        ]
    }
]

response = MultiModalConversation.call(
    # 環境変数が構成されていない場合は、Model Studio API キーに置き換えます。api_key="sk-xxx"
    api_key=os.getenv('DASHSCOPE_API_KEY'),
    model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じて他のモデル名に置き換えることができます
    messages=messages,
    stream=True,
)

# 完全な思考プロセスを定義します
reasoning_content = ""
# 完全な応答を定義します
answer_content = ""
# 思考プロセスが終了し、応答が開始されたかどうかを判断します
is_answering = False

print("=" * 20 + "推論プロセス" + "=" * 20)

for chunk in response:
    # 思考プロセスと応答の両方が空の場合は、無視します
    message = chunk.output.choices[0].message
    reasoning_content_chunk = message.get("reasoning_content", None)
    if (chunk.output.choices[0].message.content == [] and
        reasoning_content_chunk == ""):
        pass
    else:
        # 現在のチャンクが思考プロセスである場合
        if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
            print(chunk.output.choices[0].message.reasoning_content, end="")
            reasoning_content += chunk.output.choices[0].message.reasoning_content
        # 現在のチャンクが応答である場合
        elif chunk.output.choices[0].message.content != []:
            if not is_answering:
                print("\n" + "=" * 20 + "完全な応答" + "=" * 20)
                is_answering = True
            print(chunk.output.choices[0].message.content[0]["text"], end="")
            answer_content += chunk.output.choices[0].message.content[0]["text"]

# 完全な思考プロセスと完全な応答を出力する必要がある場合は、次のコードのコメントを外します
# print("=" * 20 + "完全な推論プロセス" + "=" * 20 + "\n")
# print(f"{reasoning_content}")
# print("=" * 20 + "完全な応答" + "=" * 20 + "\n")
# print(f"{answer_content}")

推論プロセスと完全な応答を表示するには、クリックしてください

====================推論プロセス====================
さて、この問題に段階的に取り組んでいきましょう。2 つの図形、直方体と立方体があります。それぞれの表面積と体積を求める必要があります。最初の図形、直方体から始めましょう。

まず、直方体の表面積の公式は 2lw + 2lh + 2wh ですよね?ここで、l は長さ、w は幅、h は高さです。図を見ると、寸法は 4 cm、3 cm、2 cm です。ちょっと待ってください、どれがどれですか?問題には「単位:cm」と書いてあるので、すべての測定値はセンチメートルです。直方体には 4、3、2 のラベルが付いています。確認してみましょう。長さは通常最も長い辺なので、おそらく 4 cm が長さ、3 cm が幅、2 cm が高さでしょう。しかし実際には、3 つの寸法すべてを正しく使用していれば、順序に関係なく公式は機能します。数字を代入すると、2*(4*3) + 2*(4*2) + 2*(3*2) になります。各部分について計算してみましょう。4*3 は 12 で、2 倍すると 24 です。4*2 は 8 で、2 倍すると 16 です。3*2 は 6 で、2 倍すると 12 です。それらを合計すると、24 + 16 は 40 で、12 を加えると 52 になります。したがって、表面積は 52 cm² になります。

直方体の体積は、長さ * 幅 * 高さです。したがって、4*3*2 です。4*3 は 12 で、2 倍すると 24 です。したがって、体積は 24 cm³ です。これは簡単そうです。

次に、立方体です。すべての辺は等しいので、各辺は 3 cm です。立方体の表面積は、1 つの面の面積の 6 倍です。各面は正方形なので、面積は 3*3=9 cm² です。6 倍すると、6*9=54 cm² になります。体積は辺の長さの 3 乗なので、3*3*3=27 cm³ です。

ちょっと待ってください、もう一度確認してみましょう。立方体の表面積は、各面が 3x3 で、6 つの面があります。はい、6*9=54 です。体積は 3^3=27 です。正しいです。

したがって、両方の計算は正しいようです。直方体の寸法を間違えていないか確認してみましょう。指定された寸法は 4、3、2 です。公式では 3 つすべてを使用するので、どれが長さ、幅、高さであっても、計算は同じはずです。したがって、2*(4*3 + 4*2 + 3*2) = 2*(12 + 8 + 6) = 2*26=52 です。はい、正しいです。体積は 4*3*2=24 です。

わかりました、これで全部だと思います。表面積と体積の両方が正しく計算されました。

====================完全な応答====================
### 解決策:

**1. 直方体 (4 cm × 3 cm × 2 cm):**

- **表面積**:  
  \[
  2(lw + lh + wh) = 2(4 \times 3 + 4 \times 2 + 3 \times 2) = 2(12 + 8 + 6) = 2 \times 26 = 52 \, \text{cm}^2
  \]

- **体積**:  
  \[
  l \times w \times h = 4 \times 3 \times 2 = 24 \, \text{cm}^3
  \]

**2. 立方体 (3 cm × 3 cm × 3 cm):**

- **表面積**:  
  \[
  6a^2 = 6 \times (3 \times 3) = 6 \times 9 = 54 \, \text{cm}^2
  \]

- **体積**:  
  \[
  a^3 = 3 \times 3 \times 3 = 27 \, \text{cm}^3
  \]

**最終的な回答**:  
1. 表面積: \(52 \, \text{cm}^2\)、体積: \(24 \, \text{cm}^3\)  
2. 表面積: \(54 \, \text{cm}^2\)、体積: \(27 \, \text{cm}^3\)

Java

サンプルコード

// dashscope SDK バージョン >= 2.19.0
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import io.reactivex.Flowable;

import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.exception.InputRequiredException;
import java.lang.System;
import com.alibaba.dashscope.utils.Constants;


public class Main {
    static {
        Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
    }
    
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    private static StringBuilder reasoningContent = new StringBuilder();
    private static StringBuilder finalContent = new StringBuilder();
    private static boolean isFirstPrint = true;

    private static void handleGenerationResult(MultiModalConversationResult message) {
        String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
        String reasoning = Objects.isNull(re)?"":re; // デフォルト値

        List> content = message.getOutput().getChoices().get(0).getMessage().getContent();
        if (!reasoning.isEmpty()) {
            reasoningContent.append(reasoning);
            if (isFirstPrint) {
                System.out.println("====================推論プロセス====================");
                isFirstPrint = false;
            }
            System.out.print(reasoning);
        }

        if (Objects.nonNull(content) && !content.isEmpty()) {
            Object text = content.get(0).get("text");
            finalContent.append(content.get(0).get("text"));
            if (!isFirstPrint) {
                System.out.println("\n====================完全な応答====================");
                isFirstPrint = true;
            }
            System.out.print(text);
        }
    }
    public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
        return MultiModalConversationParam.builder()
                // 環境変数が構成されていない場合は、Model Studio API キーに置き換えます。.apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                // 例として qvq-max を使用していますが、必要に応じて他のモデル名に置き換えることができます
                .model("qvq-max")
                .messages(Arrays.asList(Msg))
                .incrementalOutput(true)
                .build();
    }

    public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
            throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
        MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
        Flowable result = conv.streamCall(param);
        result.blockingForEach(message -> {
            handleGenerationResult(message);
        });
    }
    public static void main(String[] args) {
        try {
            MultiModalConversation conv = new MultiModalConversation();
            MultiModalMessage userMsg = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(Arrays.asList(Collections.singletonMap("image", "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"),
                            Collections.singletonMap("text", "この問題を解いてください")))
                    .build();
            streamCallWithMessage(conv, userMsg);
//             最終結果を出力します
//            if (reasoningContent.length() > 0) {
//                System.out.println("\n====================完全な応答====================");
//                System.out.println(finalContent.toString());
//            }
        } catch (ApiException | NoApiKeyException | UploadFileException | InputRequiredException e) {
            logger.error("例外が発生しました:{}", e.getMessage());
        }
        System.exit(0);
    }
}

推論プロセスと完全な応答を表示するには、クリックしてください

====================完全な応答====================
### 解決策:

**1. 直方体 (4 cm × 3 cm × 2 cm):**

- **表面積**:  
  \[
  2(lw + lh + wh) = 2(4 \times 3 + 4 \times 2 + 3 \times 2) = 2(12 + 8 + 6) = 2 \times 26 = 52 \, \text{cm}^2
  \]

- **体積**:  
  \[
  l \times w \times h = 4 \times 3 \times 2 = 24 \, \text{cm}^3
  \]

**2. 立方体 (3 cm × 3 cm × 3 cm):**

- **表面積**:  
  \[
  6a^2 = 6 \times (3 \times 3) = 6 \times 9 = 54 \, \text{cm}^2
  \]

- **体積**:  
  \[
  a^3 = 3 \times 3 \times 3 = 27 \, \text{cm}^3
  \]

**最終的な回答**:  
1. 表面積: \(52 \, \text{cm}^2\)、体積: \(24 \, \text{cm}^3\)  
2. 表面積: \(54 \, \text{cm}^2\)、体積: \(27 \, \text{cm}^3\)

HTTP

サンプルコード

curl

curl -X POST https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'X-DashScope-SSE: enable' \
-d '{
    "model": "qvq-max",
    "input":{
        "messages":[
            {
                "role": "user",
                "content": [
                    {"image": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"},
                    {"text": "この問題を解いてください"}
                ]
            }
        ]
    }
}'

思考プロセスと完全な応答を表示するには、クリックしてください

id:1
event:result
:HTTP_STATUS/200
data:{"output":{"choices":[{"message":{"content":[],"reasoning_content":"さて","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":547,"input_tokens_details":{"image_tokens":520,"text_tokens":24},"output_tokens":3,"input_tokens":544,"output_tokens_details":{"text_tokens":3},"image_tokens":520},"request_id":"f361ae45-fbef-9387-9f35-1269780e0864"}

id:2
event:result
:HTTP_STATUS/200
data:{"output":{"choices":[{"message":{"content":[],"reasoning_content":"、","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":548,"input_tokens_details":{"image_tokens":520,"text_tokens":24},"output_tokens":4,"input_tokens":544,"output_tokens_details":{"text_tokens":4},"image_tokens":520},"request_id":"f361ae45-fbef-9387-9f35-1269780e0864"}

id:3
event:result
:HTTP_STATUS/200
data:{"output":{"choices":[{"message":{"content":[],"reasoning_content":"私は","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":549,"input_tokens_details":{"image_tokens":520,"text_tokens":24},"output_tokens":5,"input_tokens":544,"output_tokens_details":{"text_tokens":5},"image_tokens":520},"request_id":"f361ae45-fbef-9387-9f35-1269780e0864"}
.....
id:566
event:result
:HTTP_STATUS/200
data:{"output":{"choices":[{"message":{"content":[{"text":"正方形"}],"role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":1132,"input_tokens_details":{"image_tokens":520,"text_tokens":24},"output_tokens":588,"input_tokens":544,"output_tokens_details":{"text_tokens":588},"image_tokens":520},"request_id":"758b0356-653b-98ac-b4d3-f812437ba1ec"}

id:567
event:result
:HTTP_STATUS/200
data:{"output":{"choices":[{"message":{"content":[{"text":"センチメートル"}],"role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":1133,"input_tokens_details":{"image_tokens":520,"text_tokens":24},"output_tokens":589,"input_tokens":544,"output_tokens_details":{"text_tokens":589},"image_tokens":520},"request_id":"758b0356-653b-98ac-b4d3-f812437ba1ec"}

id:568
event:result
:HTTP_STATUS/200
data:{"output":{"choices":[{"message":{"content":[],"role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":1134,"input_tokens_details":{"image_tokens":520,"text_tokens":24},"output_tokens":590,"input_tokens":544,"output_tokens_details":{"text_tokens":590},"image_tokens":520},"request_id":"758b0356-653b-98ac-b4d3-f812437ba1ec"}

複数ラウンドの会話

デフォルトでは、QVQ API は会話履歴を保存しません。 複数ラウンドの会話機能により、モデルは過去のやり取りを「記憶」する機能を備え、フォローアップの質問や情報収集などのシナリオに対応できます。 QVQ から reasoning_contentcontent を受け取ります。 {'role': 'assistant', 'content': 連結されたストリーミング出力コンテンツ} を使用して、コンテキストに content を含めるだけです。 reasoning_content は必須ではありません。

OpenAI

OpenAI SDK または OpenAI 互換の HTTP メソッドを介して複数ラウンドの会話を実装します。

Python

サンプルコード

from openai import OpenAI
import os

# OpenAI クライアントを初期化します
client = OpenAI(
    # 環境変数が構成されていない場合は、Model Studio API キーに置き換えます。api_key="sk-xxx"
    api_key = os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
)

messages = [
    {
        "role": "user",
        "content": [
            {
                "type": "image_url",
                "image_url": {
                    "url": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"
                },
            },
            {"type": "text", "text": "この問題を解いてください"},
        ],
    }
]
conversation_idx = 1
while True:
    reasoning_content = ""  # 完全な思考プロセスを定義します
    answer_content = ""     # 完全な応答を定義します
    is_answering = False   # 思考プロセスが終了し、応答が開始されたかどうかを判断します
    print("="*20+f"ラウンド {conversation_idx}"+"="*20)
    conversation_idx += 1
    # チャット補完リクエストを作成します
    completion = client.chat.completions.create(
        model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じて他のモデル名に置き換えることができます
        messages=messages,
        stream=True
    )
    print("\n" + "=" * 20 + "推論プロセス" + "=" * 20 + "\n")
    for chunk in completion:
        # chunk.choices が空の場合は、使用状況を出力します
        if not chunk.choices:
            print("\n使用状況:")
            print(chunk.usage)
        else:
            delta = chunk.choices[0].delta
            # 思考プロセスを出力します
            if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
                print(delta.reasoning_content, end='', flush=True)
                reasoning_content += delta.reasoning_content
            else:
                # 応答を開始します
                if delta.content != "" and is_answering is False:
                    print("\n" + "=" * 20 + "完全な応答" + "=" * 20 + "\n")
                    is_answering = True
                # 応答プロセスを出力します
                print(delta.content, end='', flush=True)
                answer_content += delta.content
    messages.append({"role": "assistant", "content": answer_content})
    messages.append({
        "role": "user",
        "content": [
        {
            "type": "text",
            "text": input("\nメッセージを入力してください:")
        }
        ]
    })
    print("\n")
    # print("=" * 20 + "完全な推論プロセス" + "=" * 20 + "\n")
    # print(reasoning_content)
    # print("=" * 20 + "完全な応答" + "=" * 20 + "\n")
    # print(answer_content)

Node.js

サンプルコード

import OpenAI from "openai";
import process from 'process';
import readline from 'readline/promises';

// readline インターフェースを初期化します
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

// openai クライアントを初期化します
const openai = new OpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY, // 環境変数から読み取ります
    baseURL: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1'
});

let reasoningContent = '';
let answerContent = '';
let isAnswering = false;
let messages = [
    {
        "role": "user",
        "content": [
            {
                "type": "image_url",
                "image_url": {
                    "url": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"
                },
            },
            {"type": "text", "text": "この問題を解いてください"},
        ],
    }
];
let conversationIdx = 1;

async function main() {
    while (true) {
        let reasoningContent = '';
        let answerContent = '';
        let isAnswering = false;
        console.log("=".repeat(20) + `ラウンド ${conversationIdx}` + "=".repeat(20));
        conversationIdx++;

        // 状態をリセットします
        reasoningContent = '';
        answerContent = '';
        isAnswering = false;

        try {
            const stream = await openai.chat.completions.create({
                model: 'qvq-max',
                messages: messages,
                stream: true
            });

            console.log("\n" + "=".repeat(20) + "推論プロセス" + "=".repeat(20) + "\n");

            for await (const chunk of stream) {
                if (!chunk.choices?.length) {
                    console.log('\n使用状況:');
                    console.log(chunk.usage);
                    continue;
                }

                const delta = chunk.choices[0].delta;

                // 思考プロセスを処理します
                if (delta.reasoning_content) {
                    process.stdout.write(delta.reasoning_content);
                    reasoningContent += delta.reasoning_content;
                }

                // 正式な応答を処理します
                if (delta.content) {
                    if (!isAnswering) {
                        console.log('\n' + "=".repeat(20) + "完全な応答" + "=".repeat(20) + "\n");
                        isAnswering = true;
                    }
                    process.stdout.write(delta.content);
                    answerContent += delta.content;
                }
            }

            // 完全な応答をメッセージ履歴に追加します
            messages.push({ role: 'assistant', content: answerContent });
            const userInput = await rl.question("メッセージを入力してください:");
            messages.push({"role": "user", "content":userInput});

            console.log("\n");

        } catch (error) {
            console.error('エラー:', error);
        }
    }
}

// プログラムを開始します
main().catch(console.error);

HTTP

サンプルコード

curl

curl -X POST https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
  "model": "qvq-max",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "image_url",
          "image_url": {
            "url": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"
          }
        },
        {
          "type": "text",
          "text": "この問題を解いてください"
        }
      ]
    },
    {
      "role": "assistant",
      "content": [
        {
          "type": "text",
          "text": "直方体:表面積は 52、体積は 24 です。立方体:表面積は 54、体積は 27 です。"
        }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "三角形の面積の公式は何ですか?"
        }
      ]
    }
  ],
    "stream":true,
    "stream_options":{"include_usage":true}
}'

DashScope

DashScope SDK または HTTP メソッドを介して複数ラウンドの会話を実装します。

Python

サンプルコード

import os
import dashscope
from dashscope import MultiModalConversation

dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
messages = [
    {
        "role": "user",
        "content": [
            {"image": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"},
            {"text": "この問題を解いてください"}
        ]
    }
]

conversation_idx = 1
while True:
    print("=" * 20 + f"ラウンド {conversation_idx}" + "=" * 20)
    conversation_idx += 1
    response = MultiModalConversation.call(
        # 環境変数が構成されていない場合は、Model Studio API キーに置き換えます。api_key="sk-xxx"
        api_key=os.getenv('DASHSCOPE_API_KEY'),
        model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じて他のモデル名に置き換えることができます
        messages=messages,
        stream=True,
    )
    # 完全な思考プロセスを定義します
    reasoning_content = ""
    # 完全な応答を定義します
    answer_content = ""
    # 思考プロセスが終了し、応答が開始されたかどうかを判断します
    is_answering = False
    print("=" * 20 + "推論プロセス" + "=" * 20)
    for chunk in response:
        # 思考プロセスと応答の両方が空の場合は、無視します
        message = chunk.output.choices[0].message
        reasoning_content_chunk = message.get("reasoning_content", None)
        if (chunk.output.choices[0].message.content == [] and
                reasoning_content_chunk == ""):
            pass
        else:
            # 現在のチャンクが思考プロセスである場合
            if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
                print(chunk.output.choices[0].message.reasoning_content, end="")
                reasoning_content += chunk.output.choices[0].message.reasoning_content
            # 現在のチャンクが応答である場合
            elif chunk.output.choices[0].message.content != []:
                if not is_answering:
                    print("\n" + "=" * 20 + "完全な応答" + "=" * 20)
                    is_answering = True
                print(chunk.output.choices[0].message.content[0]["text"], end="")
                answer_content += chunk.output.choices[0].message.content[0]["text"]
    messages.append({"role": "assistant", "content": answer_content})
    messages.append({
        "role": "user",
        "content": [
        {
            "type": "text",
            "text": input("\nメッセージを入力してください:")
        }
        ]
    })
    print("\n")
    # 完全な思考プロセスと完全な応答を出力する必要がある場合は、次のコードのコメントを外します
    # print("=" * 20 + "完全な推論プロセス" + "=" * 20 + "\n")
    # print(f"{reasoning_content}")
    # print("=" * 20 + "完全な応答" + "=" * 20 + "\n")
    # print(f"{answer_content}")

Java

サンプルコード

// dashscope SDK バージョン >= 2.19.0
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import io.reactivex.Flowable;

import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.exception.InputRequiredException;
import java.lang.System;
import com.alibaba.dashscope.utils.Constants;


public class Main {
    static {
        Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
    }
    
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    private static StringBuilder reasoningContent = new StringBuilder();
    private static StringBuilder finalContent = new StringBuilder();
    private static boolean isFirstPrint = true;

    private static void handleGenerationResult(MultiModalConversationResult message) {
        String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
        String reasoning = Objects.isNull(re)?"":re; // デフォルト値

        List> content = message.getOutput().getChoices().get(0).getMessage().getContent();
        if (!reasoning.isEmpty()) {
            reasoningContent.append(reasoning);
            if (isFirstPrint) {
                System.out.println("====================推論プロセス====================");
                isFirstPrint = false;
            }
            System.out.print(reasoning);
        }

        if (Objects.nonNull(content) && !content.isEmpty()) {
            Object text = content.get(0).get("text");
            finalContent.append(content.get(0).get("text"));
            if (!isFirstPrint) {
                System.out.println("\n====================完全な応答====================");
                isFirstPrint = true;
            }
            System.out.print(text);
        }
    }
    public static MultiModalConversationParam buildMultiModalConversationParam(List Msg)  {
        return MultiModalConversationParam.builder()
                // 環境変数が構成されていない場合は、Model Studio API キーに置き換えます。.apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                // 例として qvq-max を使用していますが、必要に応じて他のモデル名に置き換えることができます
                .model("qvq-max")
                .messages(Msg)
                .incrementalOutput(true)
                .build();
    }

    public static void streamCallWithMessage(MultiModalConversation conv, List Msg)
            throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
        MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
        Flowable result = conv.streamCall(param);
        result.blockingForEach(message -> {
            handleGenerationResult(message);
        });
    }
    public static void main(String[] args) {
        try {
            MultiModalConversation conv = new MultiModalConversation();
            MultiModalMessage userMsg1 = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(Arrays.asList(Collections.singletonMap("image", "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"),
                            Collections.singletonMap("text", "この問題を解いてください")))
                    .build();
            MultiModalMessage AssistantMsg = MultiModalMessage.builder()
                    .role(Role.ASSISTANT.getValue())
                    .content(Arrays.asList(Collections.singletonMap("text", "直方体:表面積は 52、体積は 24 です。立方体:表面積は 54、体積は 27 です。")))
                    .build();
            MultiModalMessage userMsg2 = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(Arrays.asList(Collections.singletonMap("text", "三角形の面積の公式は何ですか?")))
                    .build();
            List Msg = Arrays.asList(userMsg1,AssistantMsg,userMsg2);
            streamCallWithMessage(conv, Msg);
//             最終結果を出力します
//            if (reasoningContent.length() > 0) {
//                System.out.println("\n====================完全な応答====================");
//                System.out.println(finalContent.toString());
//            }
        } catch (ApiException | NoApiKeyException | UploadFileException | InputRequiredException e) {
            logger.error("例外が発生しました:{}", e.getMessage());
        }
        System.exit(0);
    }
}

HTTP

サンプルコード

curl

curl -X POST https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'X-DashScope-SSE: enable' \
-d '{
    "model": "qvq-max",
    "input":{
        "messages":[
            {
                "role": "user",
                "content": [
                    {"image": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"},
                    {"text": "この問題を解いてください"}
                ]
            },
            {
                "role": "assistant",
                "content": [
                    {"text": "直方体:表面積は 52、体積は 24 です。立方体:表面積は 54、体積は 27 です。"}
                ]
            },
            {
                "role": "user",
                "content": [
                    {"text": "三角形の面積の公式は何ですか?"}
                ]
            }
        ]
    }
}'

複数画像入力

QVQ は 1 回のリクエストで複数の画像を処理でき、モデルはそれらすべてに基づいて応答します。 画像は URL またはローカルファイル、あるいはその両方として入力できます。 サンプルコードは URL を使用しています。

入力画像の合計トークン数は、モデルの最大入力数未満である必要があります。 画像枚数制限 に基づいて、画像の最大枚数を計算してください。

OpenAI

Python

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

reasoning_content = ""  # 思考プロセス全体を定義
answer_content = ""     # 完全な応答を定義
is_answering = False   # 思考プロセスが終了し、応答が開始されたかどうかを判断


completion = client.chat.completions.create(
    model="qvq-max",
    messages=[
        {"role": "user", "content": [
            # 最初の画像リンク。ローカルファイルを渡す場合は、url 値を画像の Base64 エンコード形式に置き換えます
            {"type": "image_url", "image_url": {
                "url": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"}, },
            # 2 番目の画像リンク。ローカルファイルを渡す場合は、url 値を画像の Base64 エンコード形式に置き換えます
            {"type": "image_url",
             "image_url": {"url": "https://img.alicdn.com/imgextra/i1/O1CN01ukECva1cisjyK6ZDK_!!6000000003635-0-tps-1500-1734.jpg"}, },
            {"type": "text", "text": "最初の画像の質問に答え、次に 2 番目の画像の記事を解釈してください。"},
        ],
         }
    ],
    stream=True,
    # 最後のチャンクでトークンの使用状況を返すには、次のコメントを外します
    # stream_options={
    #     "include_usage": True
    # }
)
print("\n" + "=" * 20 + "Reasoning Process" + "=" * 20 + "\n")

for chunk in completion:
    # chunk.choices が空の場合は、使用状況を出力します
    if not chunk.choices:
        print("\nUsage:")
        print(chunk.usage)
    else:
        delta = chunk.choices[0].delta
        # 思考プロセスを出力
        if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
            print(delta.reasoning_content, end='', flush=True)
            reasoning_content += delta.reasoning_content
        else:
            # 応答開始
            if delta.content != "" and is_answering is False:
                print("\n" + "=" * 20 + "Complete Response" + "=" * 20 + "\n")
                is_answering = True
            # 応答プロセスを出力
            print(delta.content, end='', flush=True)
            answer_content += delta.content

# print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
# print(reasoning_content)
# print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
# print(answer_content)

Node.js

import OpenAI from "openai";
import process from 'process';

// openai クライアントを初期化
const openai = new OpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY, // 環境変数から読み込み
    baseURL: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1'
});

let reasoningContent = '';
let answerContent = '';
let isAnswering = false;

let messages = [
        {role: "user",content: [
        // 最初の画像リンク。ローカルファイルを渡す場合は、url 値を画像の Base64 エンコード形式に置き換えます
            {type: "image_url",image_url: {"url": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"}},
            // 2 番目の画像リンク。ローカルファイルを渡す場合は、url 値を画像の Base64 エンコード形式に置き換えます
            {type: "image_url",image_url: {"url": "https://img.alicdn.com/imgextra/i1/O1CN01ukECva1cisjyK6ZDK_!!6000000003635-0-tps-1500-1734.jpg"}},
            {type: "text", text: "最初の画像の質問に答え、次に 2 番目の画像の記事を解釈してください。" },
        ]}]

async function main() {
    try {
        const stream = await openai.chat.completions.create({
            model: 'qvq-max',
            messages: messages,
            stream: true
        });

        console.log('\n' + '='.repeat(20) + 'Reasoning Process' + '='.repeat(20) + '\n');

        for await (const chunk of stream) {
            if (!chunk.choices?.length) {
                console.log('\nUsage:');
                console.log(chunk.usage);
                continue;
            }

            const delta = chunk.choices[0].delta;

            // 思考プロセスを処理
            if (delta.reasoning_content) {
                process.stdout.write(delta.reasoning_content);
                reasoningContent += delta.reasoning_content;
            }
            // 正式な応答を処理
            else if (delta.content) {
                if (!isAnswering) {
                    console.log('\n' + '='.repeat(20) + 'Complete Response' + '='.repeat(20) + '\n');
                    isAnswering = true;
                }
                process.stdout.write(delta.content);
                answerContent += delta.content;
            }
        }
    } catch (error) {
        console.error('Error:', error);
    }
}

main();

curl

curl -X POST https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
  "model": "qvq-max",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "image_url",
          "image_url": {
            "url": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"
          }
        },
        {
          "type": "image_url",
          "image_url": {
            "url": "https://img.alicdn.com/imgextra/i1/O1CN01ukECva1cisjyK6ZDK_!!6000000003635-0-tps-1500-1734.jpg"
          }
        },
        {
          "type": "text",
          "text": "最初の画像の質問に答え、次に 2 番目の画像の記事を解釈してください。"
        }
      ]
    }
  ],
  "stream":true,
  "stream_options":{"include_usage":true}

}'

DashScope

Python

import os
import dashscope
from dashscope import MultiModalConversation

dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
messages = [
    {
        "role": "user",
        "content": [
            # 最初の画像リンク。ローカルファイルを渡す場合は、画像のBase64エンコード形式に置き換えてください。
            {"image": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"},
            # 2 番目の画像リンク。ローカルファイルを渡す場合は、画像のBase64エンコード形式に置き換えてください。
            {"image": "https://img.alicdn.com/imgextra/i1/O1CN01ukECva1cisjyK6ZDK_!!6000000003635-0-tps-1500-1734.jpg"},
            {"text": "最初の画像の質問に答え、次に 2 番目の画像の記事を解釈してください。"}
        ]
    }
]

response = MultiModalConversation.call(
    # 環境変数が設定されていない場合は、Model Studio API キーに置き換えてください: api_key="sk-xxx"
    api_key=os.getenv('DASHSCOPE_API_KEY'),
    model="qvq-max",  # qvq-max を例として使用していますが、必要に応じて他のモデル名に置き換えることができます
    messages=messages,
    stream=True,
)

# 思考プロセス全体を定義
reasoning_content = ""
# 完全な応答を定義
answer_content = ""
# 思考プロセスが終了し、応答が開始されたかどうかを判断
is_answering = False

print("=" * 20 + "Reasoning Process" + "=" * 20)


for chunk in response:
    # 思考プロセスと応答の両方が空の場合は無視します
    message = chunk.output.choices[0].message
    reasoning_content_chunk = message.get("reasoning_content", None)

    if (chunk.output.choices[0].message.content == [] and
        reasoning_content_chunk == ""):
        pass
    else:
        # 現在のものが思考プロセスである場合
        if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
            print(chunk.output.choices[0].message.reasoning_content, end="")
            reasoning_content += chunk.output.choices[0].message.reasoning_content
        # 現在のものが応答である場合
        elif chunk.output.choices[0].message.content != []:
            if not is_answering:
                print("\n" + "=" * 20 + "Complete Response" + "=" * 20)
                is_answering = True
            print(chunk.output.choices[0].message.content[0]["text"], end="")
            answer_content += chunk.output.choices[0].message.content[0]["text"]

# 完全な思考プロセスと完全な応答を出力する必要がある場合は、次のコードのコメントを外してください
# print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
# print(f"{reasoning_content}")
# print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
# print(f"{answer_content}")

Java

// dashscope SDK version >= 2.19.0
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import io.reactivex.Flowable;

import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.exception.InputRequiredException;
import java.lang.System;
import com.alibaba.dashscope.utils.Constants;

public class Main {
    static {
        Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
    }
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    private static StringBuilder reasoningContent = new StringBuilder();
    private static StringBuilder finalContent = new StringBuilder();
    private static boolean isFirstPrint = true;

    private static void handleGenerationResult(MultiModalConversationResult message) {
        String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
        String reasoning = Objects.isNull(re)?"":re; // デフォルト値

        List> content = message.getOutput().getChoices().get(0).getMessage().getContent();
        if (!reasoning.isEmpty()) {
            reasoningContent.append(reasoning);
            if (isFirstPrint) {
                System.out.println("====================Reasoning Process====================");
                isFirstPrint = false;
            }
            System.out.print(reasoning);
        }

        if (Objects.nonNull(content) && !content.isEmpty()) {
            Object text = content.get(0).get("text");
            finalContent.append(text);
            if (!isFirstPrint) {
                System.out.println("\n====================Complete Response====================");
                isFirstPrint = true;
            }
            System.out.print(text);
        }
    }
    public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
        return MultiModalConversationParam.builder()
                // 環境変数が設定されていない場合は、Model Studio API キーに置き換えてください:.apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                // qvq-max を例として使用していますが、必要に応じて他のモデル名に置き換えることができます
                .model("qvq-max")
                .messages(Arrays.asList(Msg))
                .incrementalOutput(true)
                .build();
    }

    public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
            throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
        MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
        Flowable result = conv.streamCall(param);
        result.blockingForEach(message -> {
            handleGenerationResult(message);
        });
    }
    public static void main(String[] args) {
        try {
            MultiModalConversation conv = new MultiModalConversation();
            MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
                    .content(Arrays.asList(
                            // 最初の画像リンク
                            Collections.singletonMap("image", "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241022/emyrja/dog_and_girl.jpeg"),
                            // ローカル画像を使用する場合は、以下の行のコメントを外してください。
                            // new HashMap(){{put("image", filePath);}},
                            // 2 番目の画像リンク
                            Collections.singletonMap("image", "https://dashscope.oss-cn-beijing.aliyuncs.com/images/tiger.png"),
                            // 3 番目の画像リンク
                            Collections.singletonMap("image", "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/hbygyo/rabbit.jpg"),
                            Collections.singletonMap("text", "これらの画像は何を描写していますか?"))).build();

            streamCallWithMessage(conv, userMessage);
//             最終結果を出力
//            if (reasoningContent.length() > 0) {
//                System.out.println("\n====================Complete Response====================");
//                System.out.println(finalContent.toString());
//            }
        } catch (ApiException | NoApiKeyException | UploadFileException | InputRequiredException e) {
            logger.error("例外が発生しました: {}", e.getMessage());
        }
        System.exit(0);
    }
}

curl

curl --location 'https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation' \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
--header 'Content-Type: application/json' \
-H 'X-DashScope-SSE: enable' \
--data '{
    "model": "qvq-max",
    "input":{
        "messages":[
            {
                "role": "user",
                "content": [
                    {"image": "https://img.alicdn.com/imgextra/i1/O1CN01gDEY8M1W114Hi3XcN_!!6000000002727-0-tps-1024-406.jpg"},
                    {"image": "https://img.alicdn.com/imgextra/i1/O1CN01ukECva1cisjyK6ZDK_!!6000000003635-0-tps-1500-1734.jpg"},
                    {"text": "最初の画像の質問に答え、次に 2 番目の画像の記事を解釈してください。"}
                ]
            }
        ]
    }
}'
 

動画理解

画像リストまたは動画ファイルとして動画を入力します。

画像リスト

最低 4 枚の画像、最大 512 枚の画像。

画像シーケンス URL のサンプルコード。ローカル動画を渡すには、ローカルファイルの使用 (Base64 エンコード) をご参照ください。

OpenAI

Python

import os
from openai import OpenAI

client = OpenAI(
    # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

reasoning_content = ""  # 完全な思考プロセスを定義する
answer_content = ""     # 完全な応答を定義する
is_answering = False   # 思考プロセスが終了し、応答が開始されたかどうかを判断する


completion = client.chat.completions.create(
    model="qvq-max",
    messages=[{"role": "user","content": [
        # 画像リストを渡す場合、ユーザーメッセージの "type" パラメーターは "video" です
        # OpenAI SDK を使用する場合、画像シーケンスはデフォルトで 0.5 秒間隔で動画から抽出され、変更はサポートされていません。フレーム抽出頻度をカスタマイズする必要がある場合は、DashScope SDK を使用してください。
        {"type": "video","video": [
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/xzsgiz/football1.jpg",
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/tdescd/football2.jpg",
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/zefdja/football3.jpg",
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/aedbqh/football4.jpg"]},
        {"type": "text","text": "この動画の具体的なプロセスを説明してください"},
    ]}],
    stream=True,
    # 最後のチャンクでトークンの使用状況を返すには、以下をコメント解除します
    # stream_options={
    #     "include_usage": True
    # }
)
print("\n" + "=" * 20 + "Reasoning Process" + "=" * 20 + "\n")

for chunk in completion:
    # chunk.choices が空の場合、使用状況を出力します
    if not chunk.choices:
        print("\nUsage:")
        print(chunk.usage)
    else:
        delta = chunk.choices[0].delta
        # 思考プロセスを出力する
        if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
            print(delta.reasoning_content, end='', flush=True)
            reasoning_content += delta.reasoning_content
        else:
            # 応答を開始する
            if delta.content != "" and is_answering is False:
                print("\n" + "=" * 20 + "Complete Response" + "=" * 20 + "\n")
                is_answering = True
            # 応答プロセスを出力する
            print(delta.content, end='', flush=True)
            answer_content += delta.content

# print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
# print(reasoning_content)
# print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
# print(answer_content)

Node.js

import OpenAI from "openai";
import process from 'process';

// openai クライアントを初期化する
const openai = new OpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY, // 環境変数から読み取る
    baseURL: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1'
});

let reasoningContent = '';
let answerContent = '';
let isAnswering = false;

let messages = [{
            role: "user",
            content: [
                {
                    // 画像リストを渡す場合、ユーザーメッセージの "type" パラメーターは "video" です
                    // OpenAI SDK を使用する場合、画像シーケンスはデフォルトで 0.5 秒間隔でビデオから抽出され、変更はサポートされていません。フレーム抽出頻度をカスタマイズする必要がある場合は、DashScope SDK を使用してください。
                    type: "video",
                    video: [
                        "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/xzsgiz/football1.jpg",
                        "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/tdescd/football2.jpg",
                        "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/zefdja/football3.jpg",
                        "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/aedbqh/football4.jpg"
                    ]
                },
                {
                    type: "text",
                    text: "このビデオの具体的なプロセスを説明してください"
                }
            ]
        }]

async function main() {
    try {
        const stream = await openai.chat.completions.create({
            model: 'qvq-max',
            messages: messages,
            stream: true
        });

        console.log('\n' + '='.repeat(20) + 'Reasoning Process' + '='.repeat(20) + '\n');

        for await (const chunk of stream) {
            if (!chunk.choices?.length) {
                console.log('\nUsage:');
                console.log(chunk.usage);
                continue;
            }

            const delta = chunk.choices[0].delta;

            // 思考プロセスを処理する
            if (delta.reasoning_content) {
                process.stdout.write(delta.reasoning_content);
                reasoningContent += delta.reasoning_content;
            }
            // 正式な応答を処理する
            else if (delta.content) {
                if (!isAnswering) {
                    console.log('\n' + '='.repeat(20) + 'Complete Response' + '='.repeat(20) + '\n');
                    isAnswering = true;
                }
                process.stdout.write(delta.content);
                answerContent += delta.content;
            }
        }
    } catch (error) {
        console.error('Error:', error);
    }
}

main();

HTTP

curl

curl -X POST https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
    "model": "qvq-max",
    "messages": [{"role": "user",
                "content": [{"type": "video",
                "video": ["https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/xzsgiz/football1.jpg",
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/tdescd/football2.jpg",
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/zefdja/football3.jpg",
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/aedbqh/football4.jpg"]},
                {"type": "text",
                "text": "このビデオの具体的なプロセスを説明してください"}]}],
    "stream":true,
    "stream_options":{"include_usage":true}
}'

DashScope

Python

import os
import dashscope

dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'

messages = [{"role": "user",
             "content": [
                 {"video":["https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/xzsgiz/football1.jpg",
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/tdescd/football2.jpg",
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/zefdja/football3.jpg",
                           "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/aedbqh/football4.jpg"],
                   "fps":2}, # qvq を使用する場合、fps パラメーターを指定できます。これは、画像シーケンスが 1/fps 秒間隔でビデオから抽出されることを示します。
                 {"text": "このビデオの具体的なプロセスを説明してください"}]}]
response = dashscope.MultiModalConversation.call(
    # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    model='qvq-max',
    messages=messages,
    stream=True
)

# 完全な思考プロセスを定義する
reasoning_content = ""
# 完全な応答を定義する
answer_content = ""
# 思考プロセスが終了し、応答が開始されたかどうかを判断する
is_answering = False

print("=" * 20 + "Reasoning Process" + "=" * 20)


for chunk in response:
    # 思考プロセスと応答の両方が空の場合は無視する
    message = chunk.output.choices[0].message
    reasoning_content_chunk = message.get("reasoning_content", None)

    if (chunk.output.choices[0].message.content == [] and
        reasoning_content_chunk == ""):
        pass
    else:
        # 現在が思考プロセスである場合
        if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
            print(chunk.output.choices[0].message.reasoning_content, end="")
            reasoning_content += chunk.output.choices[0].message.reasoning_content
        # 現在が応答である場合
        elif chunk.output.choices[0].message.content != []:
            if not is_answering:
                print("\n" + "=" * 20 + "Complete Response" + "=" * 20)
                is_answering = True
            print(chunk.output.choices[0].message.content[0]["text"], end="")
            answer_content += chunk.output.choices[0].message.content[0]["text"]

# 完全な思考プロセスと完全な応答を出力する必要がある場合は、以下のコードのコメントを解除します
# print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
# print(f"{reasoning_content}")
# print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
# print(f"{answer_content}")

Java

// dashscope SDK バージョン >= 2.19.0
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import io.reactivex.Flowable;

import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.exception.InputRequiredException;
import java.lang.System;
import com.alibaba.dashscope.utils.Constants;

public class Main {
    static {
        Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
    }
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    private static StringBuilder reasoningContent = new StringBuilder();
    private static StringBuilder finalContent = new StringBuilder();
    private static boolean isFirstPrint = true;

    private static void handleGenerationResult(MultiModalConversationResult message) {
        String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
        String reasoning = Objects.isNull(re)?"":re; // デフォルト値

        List> content = message.getOutput().getChoices().get(0).getMessage().getContent();
        if (!reasoning.isEmpty()) {
            reasoningContent.append(reasoning);
            if (isFirstPrint) {
                System.out.println("====================Reasoning Process====================");
                isFirstPrint = false;
            }
            System.out.print(reasoning);
        }

        if (Objects.nonNull(content) && !content.isEmpty()) {
            Object text = content.get(0).get("text");
            finalContent.append(text);
            if (!isFirstPrint) {
                System.out.println("\n====================Complete Response====================");
                isFirstPrint = true;
            }
            System.out.print(text);
        }
    }
    public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
        return MultiModalConversationParam.builder()
                // 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: .apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                // qvq-max を例として使用していますが、必要に応じて他のモデル名に置き換えることができます
                .model("qvq-max")
                .messages(Arrays.asList(Msg))
                .incrementalOutput(true)
                .build();
    }

    public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
            throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
        MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
        Flowable result = conv.streamCall(param);
        result.blockingForEach(message -> {
            handleGenerationResult(message);
        });
    }
    public static void main(String[] args) {
        try {
            MultiModalConversation conv = new MultiModalConversation();
            Map params = Map.of(
                    "video", Arrays.asList("https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/xzsgiz/football1.jpg",
                            "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/tdescd/football2.jpg",
                            "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/zefdja/football3.jpg",
                            "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/aedbqh/football4.jpg")
            );
            MultiModalMessage userMessage = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(Arrays.asList(
                            params,
                            Collections.singletonMap("text", "このビデオの具体的なプロセスを説明してください")))
                    .build();
            streamCallWithMessage(conv, userMessage);
// 最終結果を出力する
//            if (reasoningContent.length() > 0) {
//                System.out.println("\n====================Complete Response====================");
//                System.out.println(finalContent.toString());
//            }
        } catch (ApiException | NoApiKeyException | UploadFileException | InputRequiredException e) {
            logger.error("例外が発生しました: {}", e.getMessage());
        }
        System.exit(0);
    }}

HTTP

curl

curl -X POST https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'X-DashScope-SSE: enable' \
-d '{
  "model": "qvq-max",
  "input": {
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "video": [
              "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/xzsgiz/football1.jpg",
              "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/tdescd/football2.jpg",
              "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/zefdja/football3.jpg",
              "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241108/aedbqh/football4.jpg"
            ]

          },
          {
            "text": "このビデオの具体的なプロセスを説明してください"
          }
        ]
      }
    ]
  }
}'

動画ファイル

  • サイズ:

  • 形式:MP4、AVI、MKV、MOV、FLV、WMV。

  • 再生時間:2 秒から 10 分。

  • 寸法:制限なし。ただし、動画ファイルは約 600,000 ピクセルに調整されます。動画の寸法が大きくても、理解効果は向上しません。

  • 現在、動画ファイルの音声理解はサポートされていません。

次のサンプルコードは動画 URL 用です。ローカル動画を渡すには、ローカルファイルの使用 (Base64 エンコード) をご参照ください。

OpenAI

Python

import os
from openai import OpenAI

client = OpenAI(
    # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

reasoning_content = ""  # 完全な思考プロセスを定義する
answer_content = ""     # 完全な応答を定義する
is_answering = False   # 思考プロセスが終了し、応答が開始されたかどうかを判断する

completion = client.chat.completions.create(
    model="qvq-max",
    messages=[{"role": "user","content": [
        # 画像リストを渡す場合、ユーザーメッセージの "type" パラメーターは "video" です
        # OpenAI SDK を使用する場合、画像シーケンスはデフォルトで 0.5 秒間隔でビデオから抽出され、変更はサポートされていません。フレーム抽出頻度をカスタマイズする必要がある場合は、DashScope SDK を使用してください。
        {"type": "video_url","video_url":{"url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250328/eepdcq/phase_change_480p.mov"} },
        {"type": "text","text": "これはビデオの冒頭部分です。分析して、ビデオがどのような知識を説明しているか推測してください。"},
    ]}],
    stream=True,
    # 最後のチャンクでトークンの使用状況を返すには、以下をコメント解除します
    # stream_options={
    #     "include_usage": True
    # }
)
print("\n" + "=" * 20 + "Reasoning Process" + "=" * 20 + "\n")

for chunk in completion:
    # chunk.choices が空の場合、使用状況を出力します
    if not chunk.choices:
        print("\nUsage:")
        print(chunk.usage)
    else:
        delta = chunk.choices[0].delta
        # 思考プロセスを出力する
        if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
            print(delta.reasoning_content, end='', flush=True)
            reasoning_content += delta.reasoning_content
        else:
            # 応答を開始する
            if delta.content != "" and is_answering is False:
                print("\n" + "=" * 20 + "Complete Response" + "=" * 20 + "\n")
                is_answering = True
            # 応答プロセスを出力する
            print(delta.content, end='', flush=True)
            answer_content += delta.content

# print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
# print(reasoning_content)
# print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
# print(answer_content)

Node.js

import OpenAI from "openai";
import process from 'process';

// openai クライアントを初期化する
const openai = new OpenAI({
    apiKey: process.env.DASHSCOPE_API_KEY, // 環境変数から読み取る
    baseURL: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1'
});

let reasoningContent = '';
let answerContent = '';
let isAnswering = false;

let messages = [
    {
        role: "user",
    content: [
        // OpenAI SDK を使用する場合、画像シーケンスはデフォルトで 0.5 秒間隔でビデオから抽出され、変更はサポートされていません。フレーム抽出頻度をカスタマイズする必要がある場合は、DashScope SDK を使用してください。
        { type: "video_url", video_url: { "url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250328/eepdcq/phase_change_480p.mov" } },
        { type: "text", text: "これはビデオの冒頭部分です。分析して、ビデオがどのような知識を説明しているか推測してください。" },
    ]
}]

async function main() {
    try {
        const stream = await openai.chat.completions.create({
            model: 'qvq-max',
            messages: messages,
            stream: true
        });

        console.log('\n' + '='.repeat(20) + 'Reasoning Process' + '='.repeat(20) + '\n');

        for await (const chunk of stream) {
            if (!chunk.choices?.length) {
                console.log('\nUsage:');
                console.log(chunk.usage);
                continue;
            }

            const delta = chunk.choices[0].delta;

            // 思考プロセスを処理する
            if (delta.reasoning_content) {
                process.stdout.write(delta.reasoning_content);
                reasoningContent += delta.reasoning_content;
            }
            // 正式な応答を処理する
            else if (delta.content) {
                if (!isAnswering) {
                    console.log('\n' + '='.repeat(20) + 'Complete Response' + '='.repeat(20) + '\n');
                    isAnswering = true;
                }
                process.stdout.write(delta.content);
                answerContent += delta.content;
            }
        }
    } catch (error) {
        console.error('Error:', error);
    }
}

main();

HTTP

curl

curl --location 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions' \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
    "model": "qvq-max",
    "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "video_url",
          "video_url": {
            "url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250328/eepdcq/phase_change_480p.mov"
          }
        },
        {
          "type": "text",
          "text": "これはビデオの冒頭部分です。分析して、ビデオがどのような知識を説明しているか推測してください。"
        }
      ]
    }
  ],
    "stream":true,
    "stream_options":{"include_usage":true}
}'

DashScope

Python

import os
import dashscope
from dashscope import MultiModalConversation

dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
messages = [
    {
        "role": "user",
        "content": [
            # fps パラメーターを指定できます。これは、画像シーケンスが 1/fps 秒間隔でビデオから抽出されることを示します。手順については、https://www.alibabacloud.com/help/en/model-studio/use-qwen-by-calling-api?#2ed5ee7377fum をご参照ください。
            {"video": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250328/eepdcq/phase_change_480p.mov,"fps":2"},
            {"text": "これはビデオの冒頭部分です。分析して、ビデオがどのような知識を説明しているか推測してください。"}
        ]
    }
]

response = MultiModalConversation.call(
    # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx"
    api_key=os.getenv('DASHSCOPE_API_KEY'),
    model="qvq-max",  # qvq-max を例として使用していますが、必要に応じて他のモデル名に置き換えることができます
    messages=messages,
    stream=True,
)

# 完全な思考プロセスを定義する
reasoning_content = ""
# 完全な応答を定義する
answer_content = ""
# 思考プロセスが終了し、応答が開始されたかどうかを判断する
is_answering = False

print("=" * 20 + "Reasoning Process" + "=" * 20)

for chunk in response:
    # 思考プロセスと応答の両方が空の場合は無視する
    message = chunk.output.choices[0].message
    reasoning_content_chunk = message.get("reasoning_content", None)
    if (chunk.output.choices[0].message.content == [] and
        reasoning_content_chunk == ""):
        pass
    else:
        # 現在が思考プロセスである場合
        if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
            print(chunk.output.choices[0].message.reasoning_content, end="")
            reasoning_content += chunk.output.choices[0].message.reasoning_content
        # 現在が応答である場合
        elif chunk.output.choices[0].message.content != []:
            if not is_answering:
                print("\n" + "=" * 20 + "Complete Response" + "=" * 20)
                is_answering = True
            print(chunk.output.choices[0].message.content[0]["text"], end="")
            answer_content += chunk.output.choices[0].message.content[0]["text"]

# 完全な思考プロセスと完全な応答を出力する必要がある場合は、以下のコードのコメントを解除します
# print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
# print(f"{reasoning_content}")
# print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
# print(f"{answer_content}")

Java

// dashscope SDK バージョン >= 2.19.0
import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import io.reactivex.Flowable;

import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.common.MultiModalMessage;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.dashscope.exception.InputRequiredException;
import java.lang.System;
import com.alibaba.dashscope.utils.Constants;

public class Main {
    static {
        Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
    }
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    private static StringBuilder reasoningContent = new StringBuilder();
    private static StringBuilder finalContent = new StringBuilder();
    private static boolean isFirstPrint = true;

    private static void handleGenerationResult(MultiModalConversationResult message) {
        String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
        String reasoning = Objects.isNull(re)?"":re; // デフォルト値

        List> content = message.getOutput().getChoices().get(0).getMessage().getContent();
        if (!reasoning.isEmpty()) {
            reasoningContent.append(reasoning);
            if (isFirstPrint) {
                System.out.println("====================Reasoning Process====================");
                isFirstPrint = false;
            }
            System.out.print(reasoning);
        }

        if (Objects.nonNull(content) && !content.isEmpty()) {
            Object text = content.get(0).get("text");
            finalContent.append(content.get(0).get("text"));
            if (!isFirstPrint) {
                System.out.println("\n====================Complete Response====================");
                isFirstPrint = true;
            }
            System.out.print(text);
        }
    }
    public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
        return MultiModalConversationParam.builder()
                // 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: .apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                // qvq-max を例として使用していますが、必要に応じて他のモデル名に置き換えることができます
                .model("qvq-max")
                .messages(Arrays.asList(Msg))
                .incrementalOutput(true)
                .build();
    }

    public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
            throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
        MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
        Flowable result = conv.streamCall(param);
        result.blockingForEach(message -> {
            handleGenerationResult(message);
        });
    }
    public static void main(String[] args) {
        try {
            MultiModalConversation conv = new MultiModalConversation();
            MultiModalMessage userMsg = MultiModalMessage.builder()
                    .role(Role.USER.getValue())
                    .content(Arrays.asList(Collections.singletonMap("video", "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250328/eepdcq/phase_change_480p.mov"),
                            Collections.singletonMap("text", "これはビデオの冒頭部分です。分析して、ビデオがどのような知識を説明しているか推測してください。")))
                    .build();
            streamCallWithMessage(conv, userMsg);
// 最終結果を出力する
//            if (reasoningContent.length() > 0) {
//                System.out.println("\n====================Complete Response====================");
//                System.out.println(finalContent.toString());
//            }
        } catch (ApiException | NoApiKeyException | UploadFileException | InputRequiredException e) {
            logger.error("例外が発生しました: {}", e.getMessage());
        }
        System.exit(0);
    }}

HTTP

curl

curl -X POST https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation \
-H "Authorization: Bearer $DASHSCOPE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'X-DashScope-SSE: enable' \
-d '{
    "model": "qvq-max",
    "input":{
        "messages":[
            {
                "role": "user",
                "content": [
                    {"video": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250328/eepdcq/phase_change_480p.mov"},
                    {"text": "これはビデオの冒頭部分です。分析して、ビデオがどのような知識を説明しているか推測してください。"}
                ]
            }
        ]
    }
}'

ローカルファイルの使用(Base64 エンコードまたはファイルパス)

ローカルファイルのアップロード方法:

方法 1: ローカルファイルを Base64 形式でエンコードする(OpenAI と DashScope SDK の両方に適用可能)

Base64 エンコードファイルをアップロードするには、次の手順に従います。

Base64 エンコードファイルをアップロードする(例として画像を使用)

  1. ファイルのエンコード: 画像を Base64 形式にエンコードします。

  2. Base64 データの受け渡し: Base64 データを次の形式で image_url パラメーターに渡します: data:image/{format};base64,{base64_image}。ここで、image/{format} は画像形式を表します。画像の実際の形式に置き換え、サポートされている画像形式 テーブルの Content Type の値と一致することを確認します。たとえば、JPG 画像を使用する場合は、image/jpeg にする必要があります。

  3. モデルの呼び出し: QVQ モデルを呼び出し、返された結果を処理します。

方法 2: ファイルパスを直接渡す(DashScope SDK のみ)

プログラミング言語とオペレーティングシステムに基づいてファイルパスを作成するには、以下の表を参照してください。

ファイルパスを作成する(例として画像を使用)

システム

SDK

ファイルパスの形式

Linux または macOS

Python SDK

file://{ファイルの絶対パス}

file:///home/images/test.png

Java SDK

Windows

Python SDK

file://{ファイルの絶対パス}

file://D:/images/test.png

Java SDK

file:///{ファイルの絶対パス}

file:///D:/images/test.png

Base64 エンコードはデータ量を増やし、エンコードされた画像は 10 MB 未満である必要があります。ファイルパスを直接渡す場合は、画像自体が 10 MB 未満である必要があります。ファイルパス方式を使用すると、安定性が向上するため、推奨されます。ただし、小さい画像(1 MB 未満)の場合は、Base64 エンコード方式も許容されます。

画像

ローカルファイル test.jpg を例として使用します。

入力画像の制限事項は、使用上の注意 で確認できます。画像 URL の受け渡しについては、はじめに をご参照ください。

OpenAI

Python

from openai import OpenAI
import os
import base64


#  base 64 エンコード形式
def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode("utf-8")

# xxxx/test.jpg をローカル画像の絶対パスに置き換えます
base64_image = encode_image("xxx/test.jpg")

# OpenAI クライアントを初期化します
client = OpenAI(
    # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx"
    api_key = os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
)

reasoning_content = ""  # 推論プロセス全体を定義します
answer_content = ""     # 完全な応答を定義します
is_answering = False   # 推論プロセスが終了し、応答が開始されたかどうかを判断します

# チャット補完リクエストを作成します
completion = client.chat.completions.create(
    model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    # Base64 を渡す場合は、画像形式 (image/{format}) がサポートされている画像リストの Content Type と一致している必要があることに注意してください。 "f" は文字列フォーマットメソッドです。
                    # PNG 画像:  f"data:image/png;base64,{base64_image}"
                    # JPEG 画像: f"data:image/jpeg;base64,{base64_image}"
                    # WEBP 画像: f"data:image/webp;base64,{base64_image}"
                    "image_url": {"url": f"data:image/png;base64,{base64_image}"},
                },
                {"type": "text", "text": "この問題を解決するにはどうすればよいですか?"},
            ],
        }
    ],
    stream=True,
    # 最後のチャンクでトークンの使用状況を返すには、次のコメントを外します
    # stream_options={
    #     "include_usage": True
    # }
)

print("\n" + "=" * 20 + "Reasoning Process" + "=" * 20 + "\n")

for chunk in completion:
    # chunk.choices が空の場合は、使用状況を出力します
    if not chunk.choices:
        print("\nUsage:")
        print(chunk.usage)
    else:
        delta = chunk.choices[0].delta
        # 推論プロセスを出力します
        if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
            print(delta.reasoning_content, end='', flush=True)
            reasoning_content += delta.reasoning_content
        else:
            # 応答を開始します
            if delta.content != "" and is_answering is False:
                print("\n" + "=" * 20 + "Complete Response" + "=" * 20 + "\n")
                is_answering = True
            # 応答プロセスを出力します
            print(delta.content, end='', flush=True)
            answer_content += delta.content

# print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
# print(reasoning_content)
# print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
# print(answer_content)

Node.js

import OpenAI from "openai";
import { readFileSync } from 'fs';

const openai = new OpenAI(
    {
        // 環境変数が設定されていない場合は、次の行を Model Studio API キーに置き換えます: apiKey: "sk-xxx"
        apiKey: process.env.DASHSCOPE_API_KEY,
        baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
    }
);

const encodeImage = (imagePath) => {
    const imageFile = readFileSync(imagePath);
    return imageFile.toString('base64');
  };
// xxxx/test.jpg をローカル画像の絶対パスに置き換えます
const base64Image = encodeImage("xxx/test.jpg")
let reasoningContent = '';
let answerContent = '';
let isAnswering = false;

let messages = [
    {
        role: "user",
    content: [
        { type: "image_url", image_url: {"url": `data:image/png;base64,${base64Image}`} },
        { type: "text", text: "この問題を解決してください" },
    ]
}]

async function main() {
    try {
        const stream = await openai.chat.completions.create({
            model: 'qvq-max',
            messages: messages,
            stream: true
        });

        console.log('\n' + '='.repeat(20) + 'Reasoning Process' + '='.repeat(20) + '\n');

        for await (const chunk of stream) {
            if (!chunk.choices?.length) {
                console.log('\nUsage:');
                console.log(chunk.usage);
                continue;
            }

            const delta = chunk.choices[0].delta;

            // 推論を処理します
            if (delta.reasoning_content) {
                process.stdout.write(delta.reasoning_content);
                reasoningContent += delta.reasoning_content;
            }
            // 正式な応答を処理します
            else if (delta.content) {
                if (!isAnswering) {
                    console.log('\n' + '='.repeat(20) + 'Complete Response' + '='.repeat(20) + '\n');
                    isAnswering = true;
                }
                process.stdout.write(delta.content);
                answerContent += delta.content;
            }
        }
    } catch (error) {
        console.error('Error:', error);
    }
}

main();

DashScope

  • Base64 エンコードされたローカルファイルを渡します。

    Python

    import os
    import base64
    import dashscope 
    
    dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
    
    #  base 64 エンコード形式
    def encode_image(image_path):
        with open(image_path, "rb") as image_file:
            return base64.b64encode(image_file.read()).decode("utf-8")
    
    # xxxx/test.jpg をローカル画像の絶対パスに置き換えます
    base64_image = encode_image("xxxx/test.jpg")
    
    
    messages = [{'role':'user',
                    'content': [{'image': f"data:image/jpg;base64,{base64_image}"},
                                {'text': 'この問題を解決するにはどうすればよいですか?'}]}]
    
    
    response = dashscope.MultiModalConversation.call(
        # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx",
        api_key=os.getenv('DASHSCOPE_API_KEY'),
        model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます。
        messages=messages,
        stream=True,
    )
    
    # 推論プロセス全体を定義します
    reasoning_content = ""
    # 完全な応答を定義します
    answer_content = ""
    # 推論プロセスが終了し、応答が開始されたかどうかを判断します
    is_answering = False
    
    print("=" * 20 + "Reasoning Process" + "=" * 20)
    
    for chunk in response:
        # 推論プロセスと応答の両方が空の場合は無視します
        message = chunk.output.choices[0].message
        reasoning_content_chunk = message.get("reasoning_content", None)
    
        if (chunk.output.choices[0].message.content == [] and
            reasoning_content_chunk == ""):
            pass
        else:
            # 現在のものが推論プロセスである場合
            if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
                print(chunk.output.choices[0].message.reasoning_content, end="")
                reasoning_content += chunk.output.choices[0].message.reasoning_content
            # 現在のものが応答である場合
            elif chunk.output.choices[0].message.content != []:
                if not is_answering:
                    print("\n" + "=" * 20 + "Complete Response" + "=" * 20)
                    is_answering = True
                print(chunk.output.choices[0].message.content[0]["text"], end="")
                answer_content += chunk.output.choices[0].message.content[0]["text"]
    
    # 推論プロセス全体と完全な応答を出力するには、次のコードのコメントを外します
    # print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
    # print(f"{reasoning_content}")
    # print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
    # print(f"{answer_content}")

    Java

    // dashscope SDK バージョン >= 2.19.0
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.*;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.alibaba.dashscope.common.Role;
    import com.alibaba.dashscope.exception.ApiException;
    import com.alibaba.dashscope.exception.NoApiKeyException;
    import io.reactivex.Flowable;
    
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
    import com.alibaba.dashscope.common.MultiModalMessage;
    import com.alibaba.dashscope.exception.UploadFileException;
    import com.alibaba.dashscope.exception.InputRequiredException;
    import java.lang.System;
    import com.alibaba.dashscope.utils.Constants;
    
    public class Main {
    
        static {
            Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
        }
        
        private static final Logger logger = LoggerFactory.getLogger(Main.class);
        private static StringBuilder reasoningContent = new StringBuilder();
        private static StringBuilder finalContent = new StringBuilder();
        private static boolean isFirstPrint = true;
    
        private static String encodeImageToBase64(String imagePath) throws IOException {
            Path path = Paths.get(imagePath);
            byte[] imageBytes = Files.readAllBytes(path);
            return Base64.getEncoder().encodeToString(imageBytes);
        }
    
        private static void handleGenerationResult(MultiModalConversationResult message) {
            String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
            String reasoning = Objects.isNull(re)?"":re; // デフォルト値
    
            List<Map<String, Object>> content = message.getOutput().getChoices().get(0).getMessage().getContent();
            if (!reasoning.isEmpty()) {
                reasoningContent.append(reasoning);
                if (isFirstPrint) {
                    System.out.println("====================Reasoning Process====================");
                    isFirstPrint = false;
                }
                System.out.print(reasoning);
            }
    
            if (Objects.nonNull(content) && !content.isEmpty()) {
                Object text = content.get(0).get("text");
                finalContent.append(text);
                if (!isFirstPrint) {
                    System.out.println("\n====================Complete Response====================");
                    isFirstPrint = true;
                }
                System.out.print(text);
            }
        }
        public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
            return MultiModalConversationParam.builder()
                    // 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: .apiKey("sk-xxx")
                    .apiKey(System.getenv("DASHSCOPE_API_KEY"))//
                    // 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます
                    .model("qvq-max")
                    .messages(Arrays.asList(Msg))
                    .incrementalOutput(true)
                    .build();
        }
    
        public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
                throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
            MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
            Flowable<MultiModalConversationResult> result = conv.streamCall(param);
            result.blockingForEach(message -> {
                handleGenerationResult(message);
            });
        }
        public static void main(String[] args) {
            try {
                String localPath = "xxx/test.png";
                String base64Image = encodeImageToBase64(localPath);
                MultiModalConversation conv = new MultiModalConversation();
                MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
                        .content(Arrays.asList(new HashMap<String, Object>(){{put("image", "data:image/png;base64," + base64Image);}},
                                new HashMap<String, Object>(){{put("text", "この問題を解決してください");}})).build();
                streamCallWithMessage(conv, userMessage);
    //             最終結果を出力します
    //            if (reasoningContent.length() > 0) {
    //                System.out.println("\n====================Complete Response====================");
    //                System.out.println(finalContent.toString());
    //            }
            } catch (ApiException | NoApiKeyException | UploadFileException | IOException | InputRequiredException e) {
                logger.error("例外が発生しました: {}", e.getMessage());
            }
            System.exit(0);
        }
    }    
  • ファイルパスを直接渡します。詳細については、ファイルパスの作成 をご参照ください。

    Python

    import os
    import dashscope
    
    dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
    
    # xxxx/test.jpg をローカル画像の絶対パスに置き換えます
    local_path = "xxx/test.jpg"
    image_path = f"file://{local_path}"
    messages = [{'role':'user',
                    'content': [{'image': image_path},
                                {'text': 'この問題を解決してください'}]}]
    
    
    response = dashscope.MultiModalConversation.call(
        # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx",
        api_key=os.getenv('DASHSCOPE_API_KEY'),
        model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます。
        messages=messages,
        stream=True,
    )
    
    # 推論プロセス全体を定義します
    reasoning_content = ""
    # 完全な応答を定義します
    answer_content = ""
    # 推論プロセスが終了し、応答が開始されたかどうかを判断します
    is_answering = False
    
    print("=" * 20 + "Reasoning Process" + "=" * 20)
    
    for chunk in response:
        # 推論プロセスと応答の両方が空の場合は無視します
        message = chunk.output.choices[0].message
        reasoning_content_chunk = message.get("reasoning_content", None)
    
        if (chunk.output.choices[0].message.content == [] and
            reasoning_content_chunk == ""):
            pass
        else:
            # 現在のものが推論プロセスである場合
            if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
                print(chunk.output.choices[0].message.reasoning_content, end="")
                reasoning_content += chunk.output.choices[0].message.reasoning_content
            # 現在のものが応答である場合
            elif chunk.output.choices[0].message.content != []:
                if not is_answering:
                    print("\n" + "=" * 20 + "Complete Response" + "=" * 20)
                    is_answering = True
                print(chunk.output.choices[0].message.content[0]["text"], end="")
                answer_content += chunk.output.choices[0].message.content[0]["text"]
    
    # 推論プロセス全体と完全な応答を出力するには、次のコードのコメントを外します
    # print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
    # print(f"{reasoning_content}")
    # print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
    # print(f"{answer_content}")

    Java

    // dashscope SDK バージョン >= 2.19.0
    import java.util.*;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.alibaba.dashscope.common.Role;
    import com.alibaba.dashscope.exception.ApiException;
    import com.alibaba.dashscope.exception.NoApiKeyException;
    import io.reactivex.Flowable;
    
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
    import com.alibaba.dashscope.common.MultiModalMessage;
    import com.alibaba.dashscope.exception.UploadFileException;
    import com.alibaba.dashscope.exception.InputRequiredException;
    import java.lang.System;
    import com.alibaba.dashscope.utils.Constants;
    
    public class Main {
        static {
                Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
            }
            
        private static final Logger logger = LoggerFactory.getLogger(Main.class);
        private static StringBuilder reasoningContent = new StringBuilder();
        private static StringBuilder finalContent = new StringBuilder();
        private static boolean isFirstPrint = true;
    
        private static void handleGenerationResult(MultiModalConversationResult message) {
            String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
            String reasoning = Objects.isNull(re)?"":re; // デフォルト値
    
            List<Map<String, Object>> content = message.getOutput().getChoices().get(0).getMessage().getContent();
            if (!reasoning.isEmpty()) {
                reasoningContent.append(reasoning);
                if (isFirstPrint) {
                    System.out.println("====================Reasoning Process====================");
                    isFirstPrint = false;
                }
                System.out.print(reasoning);
            }
    
            if (Objects.nonNull(content) && !content.isEmpty()) {
                Object text = content.get(0).get("text");
                finalContent.append(text);
                if (!isFirstPrint) {
                    System.out.println("\n====================Complete Response====================");
                    isFirstPrint = true;
                }
                System.out.print(text);
            }
        }
        public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
            return MultiModalConversationParam.builder()
                    // 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: .apiKey("sk-xxx")
                    .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                    // 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます
                    .model("qvq-max")
                    .messages(Arrays.asList(Msg))
                    .incrementalOutput(true)
                    .build();
        }
    
        public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
                throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
            MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
            Flowable<MultiModalConversationResult> result = conv.streamCall(param);
            result.blockingForEach(message -> {
                handleGenerationResult(message);
            });
        }
        public static void main(String[] args) {
            try {
                String localPath = "xxx/test.png";
                String filePath = "file://"+ localPath;
                MultiModalConversation conv = new MultiModalConversation();
                MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
                        .content(Arrays.asList(new HashMap<String, Object>(){{put("image", filePath);}},
                                new HashMap<String, Object>(){{put("text", "この問題を解決してください");}})).build();
                streamCallWithMessage(conv, userMessage);
    //             最終結果を出力します
    //            if (reasoningContent.length() > 0) {
    //                System.out.println("\n====================Complete Response====================");
    //                System.out.println(finalContent.toString());
    //            }
            } catch (ApiException | NoApiKeyException | UploadFileException | InputRequiredException e) {
                logger.error("例外が発生しました: {}", e.getMessage());
            }
            System.exit(0);
        }
    }

動画

動画ファイル

ローカルファイル test.mp4 を例として使用します。

OpenAI

Python

from openai import OpenAI
import os
import base64


#  base 64 エンコード形式
def encode_video(video_path):
    with open(video_path, "rb") as video_file:
        return base64.b64encode(video_file.read()).decode("utf-8")

# xxxx/test.mp4 をローカルビデオの絶対パスに置き換えます
base64_video = encode_video("xxx/test.mp4")

# OpenAI クライアントを初期化します
client = OpenAI(
    # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx"
    api_key = os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
)

reasoning_content = ""  # 推論プロセス全体を定義します
answer_content = ""     # 完全な応答を定義します
is_answering = False   # 推論プロセスが終了し、応答が開始されたかどうかを判断します

# チャット補完リクエストを作成します
completion = client.chat.completions.create(
    model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "video_url",
                    # Base64 エンコードを渡す場合は、video/mp4 をローカルビデオの形式に応じて変更する必要があることに注意してください
                    "video_url": {"url": f"data:video/mp4;base64,{base64_video}"},
                },
                {"type": "text", "text": "このビデオは何についてですか?"},
            ],
        }
    ],
    stream=True,
    # 最後のチャンクでトークンの使用状況を返すには、次のコメントを外します
    # stream_options={
    #     "include_usage": True
    # }
)

print("\n" + "=" * 20 + "Reasoning Process" + "=" * 20 + "\n")

for chunk in completion:
    # chunk.choices が空の場合は、使用状況を出力します
    if not chunk.choices:
        print("\nUsage:")
        print(chunk.usage)
    else:
        delta = chunk.choices[0].delta
        # 推論プロセスを出力します
        if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
            print(delta.reasoning_content, end='', flush=True)
            reasoning_content += delta.reasoning_content
        else:
            # 応答を開始します
            if delta.content != "" and is_answering is False:
                print("\n" + "=" * 20 + "Complete Response" + "=" * 20 + "\n")
                is_answering = True
            # 応答プロセスを出力します
            print(delta.content, end='', flush=True)
            answer_content += delta.content

# print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
# print(reasoning_content)
# print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
# print(answer_content)

Node.js

import OpenAI from "openai";
import { readFileSync } from 'fs';

const openai = new OpenAI(
    {
        // 環境変数が設定されていない場合は、次の行を Model Studio API キーに置き換えます: apiKey: "sk-xxx"
        apiKey: process.env.DASHSCOPE_API_KEY,
        baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
    }
);

const encodeVideo = (videoPath) => {
    const videoFile = readFileSync(videoPath);
    return videoFile.toString('base64');
  };
// xxxx/test.mp4 をローカルビデオの絶対パスに置き換えます
const base64Video = encodeVideo("xxx/test.mp4")

let reasoningContent = '';
let answerContent = '';
let isAnswering = false;

let messages = [
    {
        role: "user",
    content: [
        // Base64 エンコードを渡す場合は、video/mp4 をローカルビデオの形式に応じて変更する必要があることに注意してください
        { type: "video_url", video_url: {"url": `data:video/mp4;base64,${base64Video}`} },
        { type: "text", text: "このビデオは何についてですか?" },
    ]
}]

async function main() {
    try {
        const stream = await openai.chat.completions.create({
            model: 'qvq-max',
            messages: messages,
            stream: true
        });

        console.log('\n' + '='.repeat(20) + 'Reasoning Process' + '='.repeat(20) + '\n');

        for await (const chunk of stream) {
            if (!chunk.choices?.length) {
                console.log('\nUsage:');
                console.log(chunk.usage);
                continue;
            }

            const delta = chunk.choices[0].delta;

            // 推論を処理します
            if (delta.reasoning_content) {
                process.stdout.write(delta.reasoning_content);
                reasoningContent += delta.reasoning_content;
            }
            // 正式な応答を処理します
            else if (delta.content) {
                if (!isAnswering) {
                    console.log('\n' + '='.repeat(20) + 'Complete Response' + '='.repeat(20) + '\n');
                    isAnswering = true;
                }
                process.stdout.write(delta.content);
                answerContent += delta.content;
            }
        }
    } catch (error) {
        console.error('Error:', error);
    }
}

main();

DashScope

  • Base64 エンコードされたローカルファイルを渡します。

    Python

    import base64
    import os
    import dashscope
    
    dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
    
    def encode_video(video_path):
        with open(video_path, "rb") as video_file:
            return base64.b64encode(video_file.read()).decode("utf-8")
    
    # xxxx/test.mp4 をローカルビデオの絶対パスに置き換えます
    base64_video = encode_video("xxxx/fruits.mp4")
    
    messages = [{'role':'user',
                    'content': [{'video': f"data:video/mp4;base64,{base64_video}"},
                                {'text': 'このビデオは何についてですか?'}]}]
    
    
    response = dashscope.MultiModalConversation.call(
        # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx",
        api_key=os.getenv('DASHSCOPE_API_KEY'),
        model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます。
        messages=messages,
        stream=True,
    )
    
    # 推論プロセス全体を定義します
    reasoning_content = ""
    # 完全な応答を定義します
    answer_content = ""
    # 推論プロセスが終了し、応答が開始されたかどうかを判断します
    is_answering = False
    
    print("=" * 20 + "Reasoning Process" + "=" * 20)
    
    for chunk in response:
        # 推論プロセスと応答の両方が空の場合は無視します
        message = chunk.output.choices[0].message
        reasoning_content_chunk = message.get("reasoning_content", None)
    
        if (chunk.output.choices[0].message.content == [] and
            reasoning_content_chunk == ""):
            pass
        else:
            # 現在のものが推論プロセスである場合
            if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
                print(chunk.output.choices[0].message.reasoning_content, end="")
                reasoning_content += chunk.output.choices[0].message.reasoning_content
            # 現在のものが応答である場合
            elif chunk.output.choices[0].message.content != []:
                if not is_answering:
                    print("\n" + "=" * 20 + "Complete Response" + "=" * 20)
                    is_answering = True
                print(chunk.output.choices[0].message.content[0]["text"], end="")
                answer_content += chunk.output.choices[0].message.content[0]["text"]
    
    # 推論プロセス全体と完全な応答を出力するには、次のコードのコメントを外します
    # print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
    # print(f"{reasoning_content}")
    # print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
    # print(f"{answer_content}")

    Java

    // dashscope SDK バージョン >= 2.19.0
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.*;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.alibaba.dashscope.common.Role;
    import com.alibaba.dashscope.exception.ApiException;
    import com.alibaba.dashscope.exception.NoApiKeyException;
    import io.reactivex.Flowable;
    
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
    import com.alibaba.dashscope.common.MultiModalMessage;
    import com.alibaba.dashscope.exception.UploadFileException;
    import com.alibaba.dashscope.exception.InputRequiredException;
    import java.lang.System;
    import com.alibaba.dashscope.utils.Constants;
    
    public class Main {
        static {
            Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
        }
        
        private static final Logger logger = LoggerFactory.getLogger(Main.class);
        private static StringBuilder reasoningContent = new StringBuilder();
        private static StringBuilder finalContent = new StringBuilder();
        private static boolean isFirstPrint = true;
    
        private static String encodeVideoToBase64(String videoPath) throws IOException {
            Path path = Paths.get(videoPath);
            byte[] videoBytes = Files.readAllBytes(path);
            return Base64.getEncoder().encodeToString(videoBytes);
        }
    
        private static void handleGenerationResult(MultiModalConversationResult message) {
            String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
            String reasoning = Objects.isNull(re)?"":re; // デフォルト値
    
            List<Map<String, Object>> content = message.getOutput().getChoices().get(0).getMessage().getContent();
            if (!reasoning.isEmpty()) {
                reasoningContent.append(reasoning);
                if (isFirstPrint) {
                    System.out.println("====================Reasoning Process====================");
                    isFirstPrint = false;
                }
                System.out.print(reasoning);
            }
    
            if (Objects.nonNull(content) && !content.isEmpty()) {
                Object text = content.get(0).get("text");
                finalContent.append(text);
                if (!isFirstPrint) {
                    System.out.println("\n====================Complete Response====================");
                    isFirstPrint = true;
                }
                System.out.print(text);
            }
        }
        public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
            return MultiModalConversationParam.builder()
                    // 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: .apiKey("sk-xxx")
                    .apiKey(System.getenv("DASHSCOPE_API_KEY"))//
                    // 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます
                    .model("qvq-max")
                    .messages(Arrays.asList(Msg))
                    .incrementalOutput(true)
                    .build();
        }
    
        public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
                throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
            MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
            Flowable<MultiModalConversationResult> result = conv.streamCall(param);
            result.blockingForEach(message -> {
                handleGenerationResult(message);
            });
        }
        public static void main(String[] args) {
            try {
                // xxx/test.mp4 をローカル画像の絶対パスに置き換えます
                String base64Video = encodeVideoToBase64("xxx/test.mp4");
                MultiModalConversation conv = new MultiModalConversation();
                MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
                        .content(Arrays.asList(new HashMap<String, Object>(){{put("video", "data:video/mp4;base64," + base64Video);}},
                                new HashMap<String, Object>(){{put("text", "このビデオは何についてですか?");}})).build();
                streamCallWithMessage(conv, userMessage);
    //             最終結果を出力します
    //            if (reasoningContent.length() > 0) {
    //                System.out.println("\n====================Complete Response====================");
    //                System.out.println(finalContent.toString());
    //            }
            } catch (ApiException | NoApiKeyException | UploadFileException | IOException | InputRequiredException e) {
                logger.error("例外が発生しました: {}", e.getMessage());
            }
            System.exit(0);
        }
    }
  • ファイルパスを直接渡します。詳細については、ファイルパスの作成 をご参照ください。

    Python

    import os
    import dashscope
    
    dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
    
    # xxxx/test.mp4 をローカルビデオの絶対パスに置き換えます
    local_path = "xxx/test.mp4"
    video_path = f"file://{local_path}"
    messages = [{'role':'user',
                    'content': [{'video': video_path},
                                {'text': 'この問題を解決してください'}]}]
    
    
    response = MultiModalConversation.call(
        # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx",
        api_key=os.getenv('DASHSCOPE_API_KEY'),
        model="qvq-max",  # 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます。
        messages=messages,
        stream=True,
    )
    
    # 推論プロセス全体を定義します
    reasoning_content = ""
    # 完全な応答を定義します
    answer_content = ""
    # 推論プロセスが終了し、応答が開始されたかどうかを判断します
    is_answering = False
    
    print("=" * 20 + "Reasoning Process" + "=" * 20)
    
    for chunk in response:
        # 推論プロセスと応答の両方が空の場合は無視します
        message = chunk.output.choices[0].message
        reasoning_content_chunk = message.get("reasoning_content", None)
    
        if (chunk.output.choices[0].message.content == [] and
            reasoning_content_chunk == ""):
            pass
        else:
            # 現在のものが推論プロセスである場合
            if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
                print(chunk.output.choices[0].message.reasoning_content, end="")
                reasoning_content += chunk.output.choices[0].message.reasoning_content
            # 現在のものが応答である場合
            elif chunk.output.choices[0].message.content != []:
                if not is_answering:
                    print("\n" + "=" * 20 + "Complete Response" + "=" * 20)
                    is_answering = True
                print(chunk.output.choices[0].message.content[0]["text"], end="")
                answer_content += chunk.output.choices[0].message.content[0]["text"]
    
    # 推論プロセス全体と完全な応答を出力するには、次のコードのコメントを外します
    # print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
    # print(f"{reasoning_content}")
    # print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
    # print(f"{answer_content}")

    Java

    // dashscope SDK バージョン >= 2.19.0
    import java.util.*;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.alibaba.dashscope.common.Role;
    import com.alibaba.dashscope.exception.ApiException;
    import com.alibaba.dashscope.exception.NoApiKeyException;
    import io.reactivex.Flowable;
    
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
    import com.alibaba.dashscope.common.MultiModalMessage;
    import com.alibaba.dashscope.exception.UploadFileException;
    import com.alibaba.dashscope.exception.InputRequiredException;
    import java.lang.System;
    import com.alibaba.dashscope.utils.Constants;
    
    public class Main {
        static {
            Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
        }
        
        private static final Logger logger = LoggerFactory.getLogger(Main.class);
        private static StringBuilder reasoningContent = new StringBuilder();
        private static StringBuilder finalContent = new StringBuilder();
        private static boolean isFirstPrint = true;
    
        private static void handleGenerationResult(MultiModalConversationResult message) {
            String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
            String reasoning = Objects.isNull(re)?"":re; // デフォルト値
    
            List<Map<String, Object>> content = message.getOutput().getChoices().get(0).getMessage().getContent();
            if (!reasoning.isEmpty()) {
                reasoningContent.append(reasoning);
                if (isFirstPrint) {
                    System.out.println("====================Reasoning Process====================");
                    isFirstPrint = false;
                }
                System.out.print(reasoning);
            }
    
            if (Objects.nonNull(content) && !content.isEmpty()) {
                Object text = content.get(0).get("text");
                finalContent.append(text);
                if (!isFirstPrint) {
                    System.out.println("\n====================Complete Response====================");
                    isFirstPrint = true;
                }
                System.out.print(text);
            }
        }
        public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
            return MultiModalConversationParam.builder()
                    // 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: .apiKey("sk-xxx")
                    .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                    // 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます
                    .model("qvq-max")
                    .messages(Arrays.asList(Msg))
                    .incrementalOutput(true)
                    .build();
        }
    
        public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
                throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
            MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
            Flowable<MultiModalConversationResult> result = conv.streamCall(param);
            result.blockingForEach(message -> {
                handleGenerationResult(message);
            });
        }
        public static void main(String[] args) {
            try {
                String localPath = "xxx/test.mp4";
                String filePath = "file://"+ localPath;
                MultiModalConversation conv = new MultiModalConversation();
                MultiModalMessage userMessage = MultiModalMessage.builder().role(Role.USER.getValue())
                        .content(Arrays.asList(new HashMap<String, Object>(){{put("video", filePath);}},
                                new HashMap<String, Object>(){{put("text", "このビデオは何についてですか?");}})).build();
                streamCallWithMessage(conv, userMessage);
    //             最終結果を出力します
    //            if (reasoningContent.length() > 0) {
    //                System.out.println("\n====================Complete Response====================");
    //                System.out.println(finalContent.toString());
    //            }
            } catch (ApiException | NoApiKeyException | UploadFileException | InputRequiredException e) {
                logger.error("例外が発生しました: {}", e.getMessage());
            }
            System.exit(0);
        }
    }

画像リスト

ローカルファイル football1.jpgfootball2.jpgfootball3.jpgfootball4.jpg を例として使用します。

OpenAI

Python

import os
from openai import OpenAI
import base64
def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode("utf-8")

base64_image1 = encode_image("football1.jpg")
base64_image2 = encode_image("football2.jpg")
base64_image3 = encode_image("football3.jpg")
base64_image4 = encode_image("football4.jpg")


client = OpenAI(
    # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx",
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
)

reasoning_content = ""  # 推論プロセス全体を定義します
answer_content = ""     # 完全な応答を定義します
is_answering = False   # 推論プロセスが終了し、応答が開始されたかどうかを判断します


completion = client.chat.completions.create(
    model="qvq-max",
    messages=[{"role": "user","content": [
        # 画像リストを渡す場合は、ユーザーメッセージの "type" パラメーターは "video" です
        {"type": "video","video": [
            f"data:image/png;base64,{base64_image1}",
            f"data:image/png;base64,{base64_image2}",
            f"data:image/png;base64,{base64_image3}",
            f"data:image/png;base64,{base64_image4}",]},
        {"type": "text","text": "このビデオの具体的なプロセスを説明してください。"},
    ]}],
    stream=True,
    # 最後のチャンクでトークンの使用状況を返すには、次のコメントを外します
    # stream_options={
    #     "include_usage": True
    # }
)
print("\n" + "=" * 20 + "Reasoning Process" + "=" * 20 + "\n")

for chunk in completion:
    # chunk.choices が空の場合は、使用状況を出力します
    if not chunk.choices:
        print("\nUsage:")
        print(chunk.usage)
    else:
        delta = chunk.choices[0].delta
        # 推論プロセスを出力します
        if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
            print(delta.reasoning_content, end='', flush=True)
            reasoning_content += delta.reasoning_content
        else:
            # 応答を開始します
            if delta.content != "" and is_answering is False:
                print("\n" + "=" * 20 + "Complete Response" + "=" * 20 + "\n")
                is_answering = True
            # 応答プロセスを出力します
            print(delta.content, end='', flush=True)
            answer_content += delta.content

# print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
# print(reasoning_content)
# print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
# print(answer_content)

Node.js

import OpenAI from "openai";
import { readFileSync } from 'fs';

const openai = new OpenAI(
    {
        // 環境変数が設定されていない場合は、次の行を Model Studio API キーに置き換えます: apiKey: "sk-xxx"
        apiKey: process.env.DASHSCOPE_API_KEY,
        baseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
    }
);

const encodeImage = (imagePath) => {
    const imageFile = readFileSync(imagePath);
    return imageFile.toString('base64');
  };

const base64Image1 = encodeImage("football1.jpg")
const base64Image2 = encodeImage("football2.jpg")
const base64Image3 = encodeImage("football3.jpg")
const base64Image4 = encodeImage("football4.jpg")

let reasoningContent = '';
let answerContent = '';
let isAnswering = false;
let messages = [{
            role: "user",
            content: [
                {
                    // 画像リストを渡す場合は、ユーザーメッセージの "type" パラメーターは "video" です
                    type: "video",
                    video: [
                            `data:image/png;base64,${base64Image1}`,
                            `data:image/png;base64,${base64Image2}`,
                            `data:image/png;base64,${base64Image3}`,
                            `data:image/png;base64,${base64Image4}`
                    ]
                },
                {
                    type: "text",
                    text: "このビデオの具体的なプロセスを説明してください"
                }
            ]
        }]

async function main() {
    try {
        const stream = await openai.chat.completions.create({
            model: 'qvq-max',
            messages: messages,
            stream: true
        });

        console.log('\n' + '='.repeat(20) + 'Reasoning Process' + '='.repeat(20) + '\n');

        for await (const chunk of stream) {
            if (!chunk.choices?.length) {
                console.log('\nUsage:');
                console.log(chunk.usage);
                continue;
            }

            const delta = chunk.choices[0].delta;

            // 推論を処理します
            if (delta.reasoning_content) {
                process.stdout.write(delta.reasoning_content);
                reasoningContent += delta.reasoning_content;
            }
            // 正式な応答を処理します
            else if (delta.content) {
                if (!isAnswering) {
                    console.log('\n' + '='.repeat(20) + 'Complete Response' + '='.repeat(20) + '\n');
                    isAnswering = true;
                }
                process.stdout.write(delta.content);
                answerContent += delta.content;
            }
        }
    } catch (error) {
        console.error('Error:', error);
    }
}

main();

DashScope

  • Base64 エンコードされたローカルファイルを渡します。

    Python

    import base64
    import os
    import dashscope
    
    dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
    
    #  base 64 エンコード形式
    def encode_image(image_path):
        with open(image_path, "rb") as image_file:
            return base64.b64encode(image_file.read()).decode("utf-8")
    
    base64_image1 = encode_image("football1.jpg")
    base64_image2 = encode_image("football2.jpg")
    base64_image3 = encode_image("football3.jpg")
    base64_image4 = encode_image("football4.jpg")
    
    
    messages = [{"role": "system",
                    "content": [{"text": "あなたは親切なアシスタントです。"}]},
                    {'role':'user',
                    'content': [
                        {'video':
                             [f"data:image/png;base64,{base64_image1}",
                              f"data:image/png;base64,{base64_image2}",
                              f"data:image/png;base64,{base64_image3}",
                              f"data:image/png;base64,{base64_image4}"
                             ]
                        },
                        {'text': 'このビデオの具体的なプロセスを説明してください。'}]}]
    
    
    response = dashscope.MultiModalConversation.call(
        # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx",
        api_key=os.getenv("DASHSCOPE_API_KEY"),
        model='qvq-max',
        messages=messages,
        stream=True
    )
    
    # 推論プロセス全体を定義します
    reasoning_content = ""
    # 完全な応答を定義します
    answer_content = ""
    # 推論プロセスが終了し、応答が開始されたかどうかを判断します
    is_answering = False
    
    print("=" * 20 + "Reasoning Process" + "=" * 20)
    
    
    for chunk in response:
        # 推論プロセスと応答の両方が空の場合は無視します
        message = chunk.output.choices[0].message
        reasoning_content_chunk = message.get("reasoning_content", None)
    
        if (chunk.output.choices[0].message.content == [] and
            reasoning_content_chunk == ""):
            pass
        else:
            # 現在のものが推論プロセスである場合
            if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
                print(chunk.output.choices[0].message.reasoning_content, end="")
                reasoning_content += chunk.output.choices[0].message.reasoning_content
            # 現在のものが応答である場合
            elif chunk.output.choices[0].message.content != []:
                if not is_answering:
                    print("\n" + "=" * 20 + "Complete Response" + "=" * 20)
                    is_answering = True
                print(chunk.output.choices[0].message.content[0]["text"], end="")
                answer_content += chunk.output.choices[0].message.content[0]["text"]
    
    # 推論プロセス全体と完全な応答を出力するには、次のコードのコメントを外します
    # print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
    # print(f"{reasoning_content}")
    # print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
    # print(f"{answer_content}")

    Java

    // dashscope SDK バージョン >= 2.19.0
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.*;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.alibaba.dashscope.common.Role;
    import com.alibaba.dashscope.exception.ApiException;
    import com.alibaba.dashscope.exception.NoApiKeyException;
    import io.reactivex.Flowable;
    
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
    import com.alibaba.dashscope.common.MultiModalMessage;
    import com.alibaba.dashscope.exception.UploadFileException;
    import com.alibaba.dashscope.exception.InputRequiredException;
    import java.lang.System;
    import com.alibaba.dashscope.utils.Constants;
    
    public class Main {
        static {
            Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
        }
    
        private static final Logger logger = LoggerFactory.getLogger(Main.class);
        private static StringBuilder reasoningContent = new StringBuilder();
        private static StringBuilder finalContent = new StringBuilder();
        private static boolean isFirstPrint = true;
    
        private static String encodeImageToBase64(String imagePath) throws IOException {
            Path path = Paths.get(imagePath);
            byte[] imageBytes = Files.readAllBytes(path);
            return Base64.getEncoder().encodeToString(imageBytes);
        }
    
        private static void handleGenerationResult(MultiModalConversationResult message) {
            String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
            String reasoning = Objects.isNull(re)?"":re; // デフォルト値
    
            List<Map<String, Object>> content = message.getOutput().getChoices().get(0).getMessage().getContent();
            if (!reasoning.isEmpty()) {
                reasoningContent.append(reasoning);
                if (isFirstPrint) {
                    System.out.println("====================Reasoning Process====================");
                    isFirstPrint = false;
                }
                System.out.print(reasoning);
            }
    
            if (Objects.nonNull(content) && !content.isEmpty()) {
                Object text = content.get(0).get("text");
                finalContent.append(text);
                if (!isFirstPrint) {
                    System.out.println("\n====================Complete Response====================");
                    isFirstPrint = true;
                }
                System.out.print(text);
            }
        }
        public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
            return MultiModalConversationParam.builder()
                    // 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: .apiKey("sk-xxx")
                    .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                    // 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます
                    .model("qvq-max")
                    .messages(Arrays.asList(Msg))
                    .incrementalOutput(true)
                    .build();
        }
    
        public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
                throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
            MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
            Flowable<MultiModalConversationResult> result = conv.streamCall(param);
            result.blockingForEach(message -> {
                handleGenerationResult(message);
            });
        }
        public static void main(String[] args) {
            try {
                MultiModalConversation conv = new MultiModalConversation();
                String localPath1 = "xxx/football1.jpg";
                String localPath2 = "xxx/football2.jpg";
                String localPath3 = "xxx/football3.jpg";
                String localPath4 = "xxx/football4.jpg";
                String base64Image1 = encodeImageToBase64(localPath1); // Base64 エンコード
                String base64Image2 = encodeImageToBase64(localPath2);
                String base64Image3 = encodeImageToBase64(localPath3);
                String base64Image4 = encodeImageToBase64(localPath4);
    
                MultiModalMessage userMessage = MultiModalMessage.builder()
                        .role(Role.USER.getValue())
                        .content(Arrays.asList(Collections.singletonMap("video", Arrays.asList(
                                        "data:image/jpeg;base64," + base64Image1,
                                        "data:image/jpeg;base64," + base64Image2,
                                        "data:image/jpeg;base64," + base64Image3,
                                        "data:image/jpeg;base64," + base64Image4)),
                                Collections.singletonMap("text", "このビデオの具体的なプロセスを説明してください"))).build();
                streamCallWithMessage(conv, userMessage);
    //             最終結果を出力します
    //            if (reasoningContent.length() > 0) {
    //                System.out.println("\n====================Complete Response====================");
    //                System.out.println(finalContent.toString());
    //            }
            } catch (ApiException | NoApiKeyException | UploadFileException | IOException | InputRequiredException e) {
                logger.error("例外が発生しました: {}", e.getMessage());
            }
            System.exit(0);
        }}
  • ファイルパスを直接渡します。詳細については、ファイルパスの作成 をご参照ください。

    Python

    import os
    
    import dashscope
    
    dashscope.base_http_api_url = 'https://dashscope-intl.aliyuncs.com/api/v1'
    
    local_path1 = "football1.jpg"
    local_path2 = "football2.jpg"
    local_path3 = "football3.jpg"
    local_path4 = "football4.jpg"
    
    image_path1 = f"file://{local_path1}"
    image_path2 = f"file://{local_path2}"
    image_path3 = f"file://{local_path3}"
    image_path4 = f"file://{local_path4}"
    
    messages = [{"role": "user",
                 "content": [
                     {"video":[image_path1,image_path2,image_path3,image_path4]},
                     {"text": "このビデオの具体的なプロセスを説明してください"}]}]
    response = dashscope.MultiModalConversation.call(
        # 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: api_key="sk-xxx",
        api_key=os.getenv("DASHSCOPE_API_KEY"),
        model='qvq-max',
        messages=messages,
        stream=True
    )
    
    # 推論プロセス全体を定義します
    reasoning_content = ""
    # 完全な応答を定義します
    answer_content = ""
    # 推論プロセスが終了し、応答が開始されたかどうかを判断します
    is_answering = False
    
    print("=" * 20 + "Reasoning Process" + "=" * 20)
    
    
    for chunk in response:
        # 推論プロセスと応答の両方が空の場合は無視します
        message = chunk.output.choices[0].message
        reasoning_content_chunk = message.get("reasoning_content", None)
    
        if (chunk.output.choices[0].message.content == [] and
            reasoning_content_chunk == ""):
            pass
        else:
            # 現在のものが推論プロセスである場合
            if reasoning_content_chunk != None and chunk.output.choices[0].message.content == []:
                print(chunk.output.choices[0].message.reasoning_content, end="")
                reasoning_content += chunk.output.choices[0.message.reasoning_content
            # 現在のものが応答である場合
            elif chunk.output.choices[0].message.content != []:
                if not is_answering:
                    print("\n" + "=" * 20 + "Complete Response" + "=" * 20)
                    is_answering = True
                print(chunk.output.choices[0].message.content[0]["text"], end="")
                answer_content += chunk.output.choices[0].message.content[0]["text"]
    
    # 推論プロセス全体と完全な応答を出力するには、次のコードのコメントを外します
    # print("=" * 20 + "Complete Reasoning Process" + "=" * 20 + "\n")
    # print(f"{reasoning_content}")
    # print("=" * 20 + "Complete Response" + "=" * 20 + "\n")
    # print(f"{answer_content}")

    Java

    // dashscope SDK バージョン >= 2.19.0
    import java.util.*;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.alibaba.dashscope.common.Role;
    import com.alibaba.dashscope.exception.ApiException;
    import com.alibaba.dashscope.exception.NoApiKeyException;
    import io.reactivex.Flowable;
    
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
    import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
    import com.alibaba.dashscope.common.MultiModalMessage;
    import com.alibaba.dashscope.exception.UploadFileException;
    import com.alibaba.dashscope.exception.InputRequiredException;
    import java.lang.System;
    import com.alibaba.dashscope.utils.Constants;
    
    public class Main {
        static {
            Constants.baseHttpApiUrl="https://dashscope-intl.aliyuncs.com/api/v1";
        }
        
        private static final Logger logger = LoggerFactory.getLogger(Main.class);
        private static StringBuilder reasoningContent = new StringBuilder();
        private static StringBuilder finalContent = new StringBuilder();
        private static boolean isFirstPrint = true;
    
        private static void handleGenerationResult(MultiModalConversationResult message) {
            String re = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();
            String reasoning = Objects.isNull(re)?"":re; // デフォルト値
    
            List<Map<String, Object>> content = message.getOutput().getChoices().get(0).getMessage().getContent();
            if (!reasoning.isEmpty()) {
                reasoningContent.append(reasoning);
                if (isFirstPrint) {
                    System.out.println("====================Reasoning Process====================");
                    isFirstPrint = false;
                }
                System.out.print(reasoning);
            }
    
            if (Objects.nonNull(content) && !content.isEmpty()) {
                Object text = content.get(0).get("text");
                finalContent.append(text);
                if (!isFirstPrint) {
                    System.out.println("\n====================Complete Response====================");
                    isFirstPrint = true;
                }
                System.out.print(text);
            }
        }
        public static MultiModalConversationParam buildMultiModalConversationParam(MultiModalMessage Msg)  {
            return MultiModalConversationParam.builder()
                    // 環境変数が設定されていない場合は、Model Studio API キーに置き換えます: .apiKey("sk-xxx")
                    .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                    // 例として qvq-max を使用していますが、必要に応じてモデル名を変更できます
                    .model("qvq-max")
                    .messages(Arrays.asList(Msg))
                    .incrementalOutput(true)
                    .build();
        }
    
        public static void streamCallWithMessage(MultiModalConversation conv, MultiModalMessage Msg)
                throws NoApiKeyException, ApiException, InputRequiredException, UploadFileException {
            MultiModalConversationParam param = buildMultiModalConversationParam(Msg);
            Flowable<MultiModalConversationResult> result = conv.streamCall(param);
            result.blockingForEach(message -> {
                handleGenerationResult(message);
            });
        }
        public static void main(String[] args) {
            try {
                MultiModalConversation conv = new MultiModalConversation();
                String localPath1 = "xxx/football1.jpg";
                String localPath2 = "xxx/football2.jpg";
                String localPath3 = "xxx/football3.jpg";
                String localPath4 = "xxx/football4.jpg";
                String filePath1 = "file://" + localPath1;
                String filePath2 = "file://" + localPath2;
                String filePath3 = "file://" + localPath3;
                String filePath4 = "file://" + localPath4;
    
                MultiModalMessage userMessage = MultiModalMessage.builder()
                        .role(Role.USER.getValue())
                        .content(Arrays.asList(Collections.singletonMap("video", Arrays.asList(
                                        filePath1,
                                        filePath2,
                                        filePath3,
                                        filePath4)),
                                Collections.singletonMap("text", "このビデオの具体的なプロセスを説明してください"))).build();
                streamCallWithMessage(conv, userMessage);
    //             最終結果を出力します
    //            if (reasoningContent.length() > 0) {
    //                System.out.println("\n====================Complete Response====================");
    //                System.out.println(finalContent.toString());
    //            }
            } catch (ApiException | NoApiKeyException | UploadFileException | InputRequiredException e) {
                logger.error("例外が発生しました: {}", e.getMessage());
            }
            System.exit(0);
        }}

使用方法に関する注意事項

対応 画像 フォーマット

対応している 画像 フォーマットは次のとおりです。OpenAI SDK を使用してローカル 画像 を入力する場合は、[コンテンツ タイプ] 列に従って image/{format} を設定します。

画像 フォーマット

ファイル名拡張子

コンテンツ タイプ

BMP

.bmp

image/bmp

JPEG

.jpe、.jpeg、.jpg

image/jpeg

PNG

.png

image/png

TIFF

.tif、.tiff

image/tiff

WEBP

.webp

image/webp

HEIC

.heic

image/heic

画像 サイズの制限

  • 単一の 画像 ファイルのサイズは 10 MB を超えてはなりません。OpenAI SDK を使用する場合、Base64 エンコードされた 画像 も 10 MB を超えてはなりません。詳細については、 を参照してください。

  • 画像 の幅と高さはどちらも 10 ピクセルより大きくする必要があります。縦横比は 200:1 または 1:200 を超えてはなりません。

  • モデルは理解する前に 画像 をスケーリングおよび前処理するため、単一の 画像 のピクセル数に制限はありません。画像 が大きいほど、理解のパフォーマンスが向上するとは限りません。推奨ピクセル値:

    • qvq-maxqvq-max-latest、または qvq-max-2025-03-25 への単一の 画像 入力の場合、ピクセル数は 1,003,520 を超えてはなりません。

画像 枚数の制限

複数 画像 入力の場合、画像 の枚数は、モデルのテキストと 画像 の合計トークン制限(最大入力)によって制限されます。すべての 画像 の合計トークン数は、モデルの最大入力より少なくなければなりません。

たとえば、qvq-max の最大入力は 106,496 トークンです。デフォルトのトークン制限は 画像 あたり 1,280 です。DashScope で vl_high_resolution_images を設定すると、トークン制限を 画像 あたり 16,384 に増やすことができます。入力 画像 がすべて 1280 × 1280 の場合:

画像 あたりのトークン制限

調整済み 画像

画像 トークン

画像 の最大枚数

1,280 (デフォルト)

980 x 980

1,227

86

16,384

1288 x 1288

2,118

50

API リファレンス

入力パラメーターと出力パラメーターの詳細については、「Qwen」をご参照ください。

エラーコード

呼び出しが失敗し、エラーメッセージが返された場合は、「エラーメッセージ」をご参照ください。