Skip to main content
Getting Started

DashScope Python SDK 1.x legacy usage reference

Legacy usage reference and 1.x-to-2.0 migration mapping for the DashScope Python SDK, for existing 1.x projects.

This page is for existing projects still on DashScope Python SDK 1.x. It collects the typical 1.x interface usage in one place and shows the equivalent 2.0 code.
For new projects, use SDK 2.0 directly. 1.x is in frozen maintenance (defect fixes only); 1.x and 2.0 coexist in the same dashscope package (from 2.0.1), so existing code can migrate incrementally without removing 1.x dependencies. The Assistants / Threads / Runs API family has been retired with 1.x and is no longer supported on the server side; do not use it in new code.

Interface migration mapping

Capability1.x interface2.0 interface
Text generationGeneration.call / AioGeneration.callclient.chat.completions.create
Multimodal chatMultiModalConversation.callclient.multimodal.chat.create
Image generationImageSynthesis.call/async_call/fetch/waitclient.images.generate / client.images.jobs.*
Video generationVideoSynthesis.call/async_call/fetch/waitclient.videos.generate / client.videos.jobs.*
Audio file transcriptionTranscription.async_call/fetch/waitclient.audio.asr.transcribe / client.audio.asr.jobs.*
Real-time speech recognitionRecognition.start/send_audio_frame/stopclient.audio.asr.recognize(...) context manager
Speech synthesisSpeechSynthesizer (tts_v2 callback style)client.audio.tts.synthesize/stream/connect
Text embeddingsTextEmbedding.call / BatchTextEmbeddingclient.embeddings.create / client.embeddings.jobs.*
RerankTextReRank.callclient.rerank.create
File managementFiles.upload/list/get/deleteclient.files.upload/list/get/delete
Model listModels.list/getclient.models.list/get

Client construction and authentication

1.x is configured via module-level globals; 2.0 is configured via Client constructor arguments (priority: constructor > dashscope.settings > environment variables > ~/.dashscope/config.toml).
# 1.x: globals
import os
import dashscope

dashscope.api_key = os.getenv("DASHSCOPE_API_KEY")
# Singapore (ap-southeast-1). For another region, replace ap-southeast-1 in the URL.
# API keys are region-specific. See https://docs.qwencloud.com/developer-guides/getting-started/regions
dashscope.base_http_api_url = "https://ap-southeast-1.maas.qwencloudapi.com/api/v1"
# 2.0: client construction
import os
import dashscope

# Singapore (ap-southeast-1). For another region, replace ap-southeast-1 in the URL.
# API keys are region-specific. See https://docs.qwencloud.com/developer-guides/getting-started/regions
client = dashscope.Client(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  base_url="https://ap-southeast-1.maas.qwencloudapi.com/api/v1",
)

Text generation

# 1.x
from dashscope import Generation

response = Generation.call(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  model="qwen-plus",
  messages=messages,
  result_format="message",
)
if response.status_code == 200:
  print(response.output.choices[0].message.content)
else:
  print(f"HTTP status: {response.status_code}")
  print(f"Error code: {response.code}")
  print(f"Error message: {response.message}")
# 2.0
from dashscope.v2 import DashScopeError

try:
  response = client.chat.completions.create(
    model="qwen-plus",
    messages=messages,
  )
  print(response.choices[0].message.content)
except DashScopeError as e:
  print(f"HTTP status: {e.status_code}")
  print(f"Error code: {e.code}")
  print(f"Error message: {e.message}")

Multimodal chat

# 1.x
from dashscope import MultiModalConversation

response = MultiModalConversation.call(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  model="qwen3-vl-plus",
  messages=[{
    "role": "user",
    "content": [
      {"image": "https://example.com/image.png"},
      {"text": "What is in this picture?"},
    ],
  }])
print(response.output.choices[0].message.content[0]["text"])
# 2.0: content parts shape kept, flat access
response = client.multimodal.chat.create(
  model="qwen3-vl-plus",
  messages=[{
    "role": "user",
    "content": [
      {"image": "https://example.com/image.png"},
      {"text": "What is in this picture?"},
    ],
  }])
print(response.output_text)

Image generation

# 1.x: synchronous call (blocks until done)
from dashscope import ImageSynthesis

rsp = ImageSynthesis.call(api_key=os.getenv("DASHSCOPE_API_KEY"),
                          model=ImageSynthesis.Models.wanx_v1,
                          prompt=prompt,
                          n=1,
                          style="<watercolor>",
                          size="1024*1024")
if rsp.status_code == HTTPStatus.OK:
  for result in rsp.output.results:
    print(result.url)
else:
  print("Failed, status_code: %s, code: %s, message: %s" %
        (rsp.status_code, rsp.code, rsp.message))
# 2.0: generate one-shot (submit and wait); enum classes become strings
job = client.images.generate(
  model="wanx2.1-t2i-turbo",
  prompt=prompt,
  n=1,
  size="1024*1024",
)
for url in job.image_urls:
  print(url)
Step-by-step tasks (1.x async_call/fetch/wait) map to client.images.jobs.create/fetch/wait; task status changes from rsp.output.task_status == "SUCCEEDED" to job.succeeded.

Video generation

# 1.x
from dashscope import VideoSynthesis

rsp = VideoSynthesis.call(api_key=api_key,
                          model="wan3.0-video",
                          prompt=prompt,
                          resolution="720P",
                          ratio="16:9",
                          duration=15,
                          watermark=True)
if rsp.status_code == HTTPStatus.OK:
  print("video_url:", rsp.output.video_url)
# 2.0
job = client.videos.generate(
  model="wan3.0-video",
  prompt=prompt,
  resolution="720P",
  ratio="16:9",
  duration=15,
  watermark=True,
)
print("video_url:", job.video_url)
In 1.x, VideoSynthesis extend_prompt defaults to True; in 2.0 it is prompt_extend and the default is decided by the server. Calls that relied on the old default must pass prompt_extend=True explicitly.

Audio file transcription

# 1.x: async_call submit + wait
import json
from dashscope.audio.asr import Transcription

task_response = Transcription.async_call(
  model="paraformer-v2",
  file_urls=["{YOUR_AUDIO_URL}"],
  language_hints=["zh", "en"],
)
transcribe_response = Transcription.wait(task=task_response.output.task_id)
if transcribe_response.status_code == HTTPStatus.OK:
  print(json.dumps(transcribe_response.output, indent=4, ensure_ascii=False))
# 2.0: transcribe one-shot; out-of-signature parameters go in parameters
job = client.audio.asr.transcribe(
  ["{YOUR_AUDIO_URL}"],
  model="paraformer-v2",
  parameters={"language_hints": ["zh", "en"]},
)
print(json.dumps(job.model_dump(), indent=4, ensure_ascii=False))
Step-by-step control (1.x async_call + fetch loop) maps to client.audio.asr.jobs.create + a jobs.fetch loop.

Real-time speech recognition

1.x uses a callback class (Recognition + RecognitionCallback); 2.0 uses a context manager with event iteration.
# 1.x (callback style, excerpt)
from dashscope.audio.asr import Recognition

class Callback(RecognitionCallback):
  def on_result(self, result): ...
recognition = Recognition(model="paraformer-realtime-v2", callback=Callback())
recognition.start()
recognition.send_audio_frame(chunk)
recognition.stop()
# 2.0 (event iteration; sending and receiving run concurrently)
from concurrent.futures import ThreadPoolExecutor

def receive_events(rec):
  for event in rec.events():
    print(event)

with client.audio.asr.recognize(
    model="paraformer-realtime-v2",
    format="pcm",
    sample_rate=16000,
) as recognition:
  with ThreadPoolExecutor(max_workers=1) as pool:
    receiver = pool.submit(receive_events, recognition)
    for chunk in iter_pcm_chunks():  # real-time PCM frames provided by the app
      recognition.send_audio_frame(chunk)
    recognition.stop()
    receiver.result()
One-shot recognition of a local file (1.x Recognition.call(file)) maps to for event in client.audio.asr.recognize_file(path, model=...):.

Speech synthesis

1.x tts_v2 collects audio through callbacks; 2.0 uses iteration or sessions.
# 1.x (callback style, excerpt)
from dashscope.audio.tts_v2 import SpeechSynthesizer, ResultCallback

class Callback(ResultCallback):
  def on_data(self, data: bytes): audio.write(data)
synthesizer = SpeechSynthesizer(
  model="cosyvoice-v3-flash",
  voice="longanyang",
  callback=Callback(),
)
synthesizer.streaming_call(text)
synthesizer.streaming_complete()
# 2.0: connect session (send text in segments, receive audio in chunks)
with client.audio.tts.connect(
    model="cosyvoice-v3-flash",
    voice="longanyang",
    format="mp3",
) as session:
  session.send_text(text)
  session.flush()
  session.stop()  # finish the task and wait for the remaining audio
  for chunk in session.audio_chunks():
    audio.write(chunk)
For one-shot synthesis (short text returned as a whole), use client.audio.tts.synthesize(text, model=..., voice=...); for pure streaming, iterate bytes from client.audio.tts.stream(text, ...).

Text embeddings and rerank

# 1.x
import dashscope

resp = dashscope.TextEmbedding.call(
  model="qwen3.7-text-embedding",
  input="The quality of the clothes is excellent",
)
if resp.status_code == HTTPStatus.OK:
  print(resp)
# 2.0
resp = client.embeddings.create(
  model="qwen3.7-text-embedding",
  input="The quality of the clothes is excellent",
)
for item in resp.embeddings:
  print(item.index, len(item.embedding))
Batch embeddings (1.x BatchTextEmbedding) map to client.embeddings.jobs.create/fetch/wait. Rerank TextReRank.call maps to client.rerank.create, and results move from resp.output.results[i] to resp.results[i].

Behavior differences

Beyond interface names, note the following behavior changes when migrating:
  • Error handling: 1.x checks status_code/code on the response object; 2.0 raises the DashScopeError family by default (e.code/e.status_code/e.request_id/e.message). For envelope-style handling, construct Client(raise_on_error=False).
  • Streaming: 1.x Generation.call(stream=True) replays the full text in every frame by default (incremental_output=True is required for deltas); 2.0 streaming is always incremental.
  • Async task waiting: 1.x wait waits indefinitely by default and returns an error response on timeout; 2.0 jobs.wait has a 24-hour budget, polls with exponential backoff, and raises when a task FAILED.
  • Response structure: 1.x wraps business content under output (response.output.choices[...]); 2.0 flattens it (response.choices[...]) and adds conveniences such as resp.output_text and job.succeeded.
  • Out-of-signature parameters: 2.0 resource methods have closed named signatures; model-specific parameters that 1.x passed through must use parameters={...} (image material inputs use extra_input=).