官网:https://help.aliyun.com/zh/model-studio/use-qwen-by-calling-api#b1320a1664b9a

创建网络请求

  1. 创建一个BaseNetworkApi基类用于实现各种拦截器等。
abstract class BaseNetworkApi {

    fun <T> getApi(serviceClass: Class<T>, baseUrl: String): T {
        val retrofitBuilder = Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(okHttpClient)
        return setRetrofitBuilder(retrofitBuilder).build().create(serviceClass)
    }

    /**
     * 实现重写父类的setHttpClientBuilder方法,
     * 在这里可以添加拦截器,可以对 OkHttpClient.Builder 做任意操作
     */
    abstract fun setHttpClientBuilder(builder: OkHttpClient.Builder): OkHttpClient.Builder

    /**
     * 实现重写父类的setRetrofitBuilder方法,
     * 在这里可以对Retrofit.Builder做任意操作,比如添加GSON解析器,Protocol
     */
    abstract fun setRetrofitBuilder(builder: Retrofit.Builder): Retrofit.Builder

    /**
     * 配置http
     */
    private val okHttpClient: OkHttpClient
        get() {
            var builder = RetrofitUrlManager.getInstance().with(OkHttpClient.Builder())
            builder = setHttpClientBuilder(builder)
            return builder.build()
        }
}
  1. 完成BaseNetworkApi的具体实现类。
val aiService : AiService by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
    AiApi.INSTANCE.getApi(AiService::class.java, AiService.getBaseUrl())
}

class AiApi : BaseNetworkApi() {

    companion object {
        val INSTANCE: AiApi by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            AiApi()
        }
    }

    /**
     * 实现重写父类的setHttpClientBuilder方法,
     * 在这里可以添加拦截器,可以对 OkHttpClient.Builder 做任意操作
     */
    override fun setHttpClientBuilder(builder: OkHttpClient.Builder): OkHttpClient.Builder {
        builder.apply {
            //设置缓存配置 缓存最大10M
            cache(Cache(File(appContext.cacheDir, "cxk_cache"), 10 * 1024 * 1024))
            //添加Cookies自动持久化
            cookieJar(cookieJar)
            addInterceptor(AiInterceptor())
            //超时时间 连接、读、写
            connectTimeout(10, TimeUnit.SECONDS)
            readTimeout(120, TimeUnit.SECONDS)
            writeTimeout(30, TimeUnit.SECONDS)
        }
        return builder
    }

    /**
     * 实现重写父类的setRetrofitBuilder方法,
     * 在这里可以对Retrofit.Builder做任意操作,比如添加GSON解析器,protobuf等
     */
    override fun setRetrofitBuilder(builder: Retrofit.Builder): Retrofit.Builder {
        return builder.apply {
            addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
        }
    }

    val cookieJar: PersistentCookieJar by lazy {
        PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(appContext))
    }

}
  1. 在AiInterceptor完成公共Header的添加。
class AiInterceptor : Interceptor {
    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val builder = chain.request().newBuilder()
        builder.addHeader("Authorization", "Bearer sk-xxxxxxxxxxxxxxxxxxxx")
        builder.addHeader("Content-Type", "application/json")
            .build()
        return chain.proceed(builder.build())
    }
}

此处的Key可在阿里云百炼自行申请。

  1. 通过第三方框架retrofit2完成网络请求注解。

interface AiService {

    companion object {
        fun getBaseUrl(): String {
            return "https://dashscope.aliyuncs.com"
        }
    }

    @POST("compatible-mode/v1/chat/completions")
    suspend fun askQuestion(@Body request: AiRequest): AiResponse<List<Choice>>
}

@Keep
data class AiResponse<T>(val error: Error?, val choices: T) : BaseResponse<T>() {

    override fun isSucces() = error ==  null

    override fun getResponseCode(): Int {
        return if (error == null) {
            200
        } else {
            400
        }
    }

    override fun getResponseData() = choices

    override fun getResponseMsg(): String {
        return error?.message?: ""
    }
}

data class Error(val message: String?, val type: String?, val param: String?, val code: String?)

data class Message(var role: String?, var content: String?)

data class Choice(var message: Message?,  var finish_reason: String?,  var index: Int?)

data class AiRequest(var model: String?, var messages: List<Message>?, var stream :Boolean? = false)

@Keep
abstract class BaseResponse<T> {
    abstract fun isSucces(): Boolean

    abstract fun getResponseData(): T

    abstract fun getResponseCode(): Int

    abstract fun getResponseMsg(): String

}
  1. 在需要的地方直接调用即可,亦可编辑请求类对异常情况进行处理。
        val message = Message("user", "你好")
        val messageList = ArrayList<Message>()
        messageList.add(message)
        val request1 = AiRequest("qwen-max", messageList)
        lifecycleScope.launch {
            val response = aiService.askQuestion(request1)
            Log.d("AI-test", response.toString())
        }

在这里插入图片描述

  1. 实现效果如下。

在这里插入图片描述

  1. 遇到的问题

● 在请求时,报java.net.SocketTimeoutException: timeout

遇到的 java.net.SocketTimeoutException: timeout 是网络请求超时问题,在调用阿里通义千问API时很常见。以下是建议方案:

① 增加超时时间配置

            connectTimeout(10, TimeUnit.SECONDS)
            readTimeout(120, TimeUnit.SECONDS)
            writeTimeout(30, TimeUnit.SECONDS)

② 网络状态检查
③ 使用 qwen-turbo,响应速度最快

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐