html对接阿里云百炼AI大模型

HTML集成阿里云百炼AI实战

一、阿里云百炼

1、什么是阿里云百炼?

阿里云百炼​ 是阿里云推出的一站式大模型应用开发平台,为企业提供全流程的大模型应用构建、调试、部署和管理服务。
核心定位

  • 企业级大模型应用开发平台
  • 全生命周期管理工具
  • 多模型集成服务平台
  • 可视化应用构建环境

2、平台核心功能

  1. 模型服务
模型服务模型类型代表模型主要用途
对话模型通义千问系列Qwen-Turbo Qwen-Plus Qwen-Max文本生成、问答对话、内容创作
图像模型通义万相系列Wanx-v1 Wanx2.1-base Wanx2.1-turbo文生图、图生图、图像编辑
代码模型通义灵码CodeQwen-7B CodeQwen-14B代码生成、代码解释、代码优化
多模态模型通义多模态Qwen-VL Qwen-VL-Chat视觉理解、多模态交互、文档分析
  1. 模型系列
    通义千问:Qwen-72B、Qwen-14B、Qwen-7B、Qwen-1.8B
    通义万相:wanx-v1、wanx-2.0、wan2.5-t2i-preview
    通义灵码:CodeQwen系列
    第三方模型:ChatGLM、Baichuan、InternLM等

3、技术架构

三层架构
┌─────────────────────────────────────────┐
│ 应用层 (Application Layer) │
│ • 可视化编排 │
│ • 应用调试 │
│ • 版本管理 │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 平台层 (Platform Layer) │
│ • 模型管理 │
│ • 数据管理 │
│ • 评估优化 │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 引擎层 (Engine Layer) │
│ • 推理服务 │
│ • 微调训练 │
│ • 向量引擎 │
└─────────────────────────────────────────┘

4、主要API服务

  1. 文本生成API
// 基础调用
POST https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation

// 请求示例
{
  "model": "qwen-turbo",
  "input": {
    "messages": [
      {
        "role": "user",
        "content": "你好"
      }
    ]
  },
  "parameters": {
    "result_format": "text"
  }
}
  1. 图片生成API
// 异步调用
POST https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis

// 请求头
{
  "Content-Type": "application/json",
  "Authorization": "Bearer sk-your-api-key",
  "X-DashScope-Async": "enable"
}

// 请求体
{
  "model": "wanx-v1",
  "input": {
    "prompt": "一只可爱的猫"
  },
  "parameters": {
    "size": "1024 * 1024",
    "n": 1
  }
}
  1. 任务查询API
// 查询异步任务状态
GET https://dashscope.aliyuncs.com/api/v1/tasks/{task_id}

5、开发工具和SDK

1. SDK支持

  • Python SDK: pip install dashscope
  • Java SDK: Maven依赖
  • Node.js SDK: npm install @alicloud/bailian
  • Go SDK: go get github.com/alibabacloud-go/bailian

2. Python SDK示例

import dashscope

3. 设置API密钥

dashscope.api_key = "sk-your-api-key"

4. 文本生成

response = dashscope.Generation.call(
    model="qwen-turbo",
    messages=[{"role": "user", "content": "你好"}]
)
print(response.output.text)

5. 图片生成

response = dashscope.ImageSynthesis.call(
    model="wanx-v1",
    prompt="一只可爱的猫",
    n=1,
    size="1024 * 1024"
)
print(response.output.results[0].url)

6、核心特性

  1. 可视化应用编排
  • 拖拽式工作流设计
  • 多节点连接
  • 实时调试
  • 版本对比
  1. 模型管理
  • 多模型统一接入
  • 模型版本管理
  • 性能监控
  • 成本分析
  1. 数据管理
  • 数据集管理
  • 数据标注
  • 数据质量评估
  • 数据版本控制
  1. 评估优化
  • 自动评估指标
  • A/B测试
  • 性能优化建议成本优化

7、计费模式

  1. 按量计费
模型类型计费单位参考价格
通义千问每千tokens0.008元/1K tokens
通义万相每张图片1.2元/张
通义灵码每千tokens0.012元/1K tokens
  1. 资源包
  • 预付费资源包
  • 阶梯折扣
  • 有效期管理
  1. 免费额度
  • 新用户赠送体验额度
  • 开发者测试额度
  • 教育科研优惠

8、应用场景

  1. 智能客服
// 客服机器人示例
{
  "model": "qwen-plus",
  "input": {
    "messages": [
      {
        "role": "system",
        "content": "你是一个专业的客服助手,回答要礼貌、准确、简洁。"
      },
      {
        "role": "user",
        "content": "我的订单什么时候发货?"
      }
    ]
  }
}
  1. 内容创作
  • 文章写作
  • 营销文案
  • 社交媒体内容
  • 视频脚本
  1. 代码助手
  • 代码生成
  • 代码解释
  • Bug修复
  • 代码优化
  1. 设计生成
  • 海报设计
  • Logo设计
  • UI界面
  • 产品原型

9、快速开始

  1. 注册账号
  • 访问官网
  • 注册阿里云账号
  • 完成实名认证
  • 申请百炼服务
  1. 获取API密钥
# 控制台操作路径
控制台 → 百炼 → 模型服务 → API-KEY管理
  1. 创建应用
// 1. 创建对话应用
模型:qwen-turbo
用途:智能客服

// 2. 创建图片应用
模型:wanx-v1
用途:产品设计

// 3. 创建工作流应用
节点:文本生成 → 图片生成 → 内容审核

10、完整项目配置

  1. 项目结构
ai-project/
├── server.js          # 代理服务器
├── client.html        # 前端界面
├── package.json       # 项目配置
├── .env              # 环境变量
└── README.md         # 项目说明
  1. 环境配置
# 安装依赖
npm init -y
npm install express cors axios

# 创建.env文件
API_KEY=sk-your-api-key
PORT=3000
  1. 启动命令
// package.json
{
  "scripts": {
    "start": "node server.js",
    "dev": "node --watch server.js",
    "test": "node test-api.js"
  }
}

11、最佳实践

  1. 错误处理
try {
  const response = await axios.post(apiUrl, data, { headers });
  return response.data;
} catch (error) {
  if (error.response) {
    // API错误
    console.error('API Error:', error.response.status, error.response.data);
  } else if (error.request) {
    // 网络错误
    console.error('Network Error:', error.message);
  } else {
    // 配置错误
    console.error('Config Error:', error.message);
  }
  throw error;
}
  1. 性能优化
// 1. 使用异步处理
app.post('/api/image', async (req, res) => {
  const task = await submitImageTask(req.body);
  res.json({ task_id: task.id });
});

// 2. 实现轮询
async function pollTask(taskId, maxAttempts = 30) {
  for (let i = 0; i < maxAttempts; i++) {
    const status = await getTaskStatus(taskId);
    if (status === 'SUCCEEDED') return await getResult(taskId);
    await sleep(2000);
  }
  throw new Error('Timeout');
}
  1. 安全实践
// 1. 环境变量管理
const API_KEY = process.env.API_KEY;

// 2. 输入验证
function validateInput(input) {
  if (!input || input.trim().length === 0) {
    throw new Error('输入不能为空');
  }
  if (input.length > 1000) {
    throw new Error('输入过长');
  }
  return input.trim();
}

12、学习资源

  1. 官方文档
  1. 学习路径
 入门  →  基础  → 进阶  →  专家  
  ↓       ↓       ↓       ↓ 
API调用 应用开发  模型微调  平台部署   
  ↓       ↓       ↓       ↓ 
文档阅读 示例学习  项目实战  架构设计

13、常见问题

Q1: API调用失败?

# 检查步骤
1. 验证API密钥
2. 检查网络连接
3. 查看账户余额
4. 确认模型可用性

Q2: 图片生成慢?

// 优化建议
1. 使用异步接口
2. 实现轮询机制
3. 设置超时时间
4. 使用回调通知

Q3: 如何计费?

# 查看账单
控制台 → 费用中心 → 账单管理
# 设置预算
控制台 → 费用中心 → 预算管理

14、总结

阿里云百炼大模型平台提供:
✅ 一站式大模型应用开发
✅ 多模型统一接入
✅ 可视化应用编排
✅ 企业级安全可靠
✅ 弹性计费模式
✅ 丰富的开发者工具
无论您是初学者还是企业开发者,百炼都能提供从模型调用到应用部署的全链路支持

二、购买百炼AI模型

1、阿里云官方渠道

  • 官网购买:访问 阿里云百炼产品
  • 控制台开通:登录阿里云控制台 → 搜索"百炼" → 立即开通

2、购买步骤

1. 注册/登录阿里云账号
2. 完成实名认证和企业认证(如需企业服务)
3. 进入百炼产品页面
4. 选择服务套餐:
   - 按量付费:适合测试和低频使用
   - 包年包月:适合稳定生产使用
5. 在线支付开通

3、API接入方式

# 1. 创建AccessKey
阿里云控制台 → 访问控制 → 创建AccessKey

# 2. 获取百炼API Endpoint
https://dashscope.aliyuncs.com/compatible-mode/v1

# 3. 设置请求头
Authorization: Bearer ${api_key}

三、HTML代码实战

1、测试

1.1 创建test.js

const axios = require('axios');

const API_KEY='sk-xxxxx'

testApiKey();

async function testApiKey() {

    try {
        const authHeader = `Bearer ${API_KEY}`;

        // 测试2: 发送请求
        console.log('\n  🔄 发送测试请求到阿里云API...');

        const response = await axios.post(
            'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation',
            {
                model: "qwen-turbo",
                input: {
                    messages: [{
                        role: "user",
                        content: "Hello"
                    }]
                },
                parameters: {
                    result_format: "text"
                }
            },
            {
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': authHeader
                },
                timeout: 10000
            }
        );

        console.log('  ✅ 请求成功!状态码:', response.status);
        console.log('  响应数据:', JSON.stringify(response.data, null, 2));

    } catch (error) {
        console.log('  ❌ 请求失败:');

        if (error.response) {
            console.log('  状态码:', error.response.status);
            console.log('  错误信息:', JSON.stringify(error.response.data, null, 2));

            if (error.response.status === 401 || error.response.status === 403) {
                console.log('  🔴 认证失败!API密钥无效');
            } else if (error.response.status === 400) {
                console.log('  🔴 请求格式错误');
                if (error.response.data?.error?.includes('Authorization')) {
                    console.log('  🔴 Authorization头部包含非法字符');
                }
            }
        } else {
            console.log('  错误:', error.message);
        }
    }
}

1.2 测试JS

使用node.js 命令
PS H:Ai>npm init -y
PS H:Ai>node test.js

返回结果

PS H:Ai> node test.js
  🔄 发送测试请求到阿里云API...
  ✅ 请求成功!状态码: 200
  响应数据: {
  "output": {
    "finish_reason": "stop",
    "text": "Hello! How can I assist you today? 😊"
  },
  "usage": {
    "input_tokens": 13,
    "output_tokens": 11,
    "prompt_tokens_details": {
      "cached_tokens": 0
    },
    "total_tokens": 24
  },
  "request_id": "cde24ffc-187e-4f50-adfc-6567ef161d1e"
}
PS H:Ai>

2、HTML实战

2.1 创建test.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI文生图测试</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
        }

        body {
            background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
            color: #333;
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 500px;
            margin: 0 auto;
        }

        .header {
            text-align: center;
            margin-bottom: 40px;
            color: white;
        }

        .header h1 {
            font-size: 42px;
            margin-bottom: 15px;
            font-weight: 700;
            text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
        }

        .header p {
            font-size: 18px;
            opacity: 0.9;
            max-width: 600px;
            margin: 0 auto;
            line-height: 1.6;
        }

        .generator-card {
            background: white;
            border-radius: 16px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
            overflow: hidden;
            transition: transform 0.3s, box-shadow 0.3s;
        }

        .generator-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
        }

        .card-header {
            padding: 25px 30px;
            color: white;
            text-align: center;
            background: linear-gradient(135deg, #ff6b6b 0%, #ff8e53 100%);
        }

        .card-header h2 {
            font-size: 24px;
            margin-bottom: 10px;
        }

        .card-header p {
            opacity: 0.9;
            font-size: 15px;
        }

        .card-content {
            padding: 25px 30px;
        }

        .input-label {
            display: block;
            margin-bottom: 12px;
            font-weight: 600;
            color: #444;
            font-size: 16px;
        }

        .input-hint {
            font-size: 14px;
            color: #666;
            margin-top: 5px;
            margin-bottom: 15px;
        }

        .text-input {
            width: 100%;
            min-height: 150px;
            padding: 15px;
            border: 2px solid #e1e5ee;
            border-radius: 10px;
            font-size: 15px;
            line-height: 1.6;
            resize: vertical;
            transition: all 0.3s;
        }

        .text-input:focus {
            outline: none;
            border-color: #2575fc;
            box-shadow: 0 0 0 3px rgba(37, 117, 252, 0.1);
        }

        .btn {
            padding: 12px 24px;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s;
            width: 100%;
            margin-top: 15px;
            background: linear-gradient(135deg, #ff6b6b 0%, #ff8e53 100%);
            color: white;
        }

        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
        }

        .btn:disabled {
            opacity: 0.6;
            cursor: not-allowed;
            transform: none !important;
        }

        .footer {
            text-align: center;
            padding: 30px;
            color: white;
            font-size: 15px;
            opacity: 0.9;
        }

        /* 结果展示样式 */
        .result-container {
            margin-top: 20px;
            padding: 15px;
            border-radius: 10px;
            background: #f8f9fa;
            text-align: center;
        }
        .loading {
            color: #666;
            font-size: 14px;
            padding: 15px;
        }
        .loading::before {
            content: "";
            display: inline-block;
            width: 20px;
            height: 20px;
            border: 3px solid #f3f3f3;
            border-top: 3px solid #2575fc;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin-right: 8px;
            vertical-align: middle;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        .error {
            color: #ff6b6b;
            padding: 15px;
            background: #fff5f5;
            border-radius: 8px;
            margin: 10px 0;
        }
        .success {
            color: #28a745;
            padding: 15px;
            background: #f0fff4;
            border-radius: 8px;
            margin: 10px 0;
            font-weight: 600;
        }
        .result-img {
            max-width: 100%;
            border-radius: 12px;
            margin: 15px 0;
            box-shadow: 0 5px 20px rgba(0,0,0,0.15);
            border: 3px solid white;
        }
        .download-btn {
            padding: 12px 24px;
            background: #2575fc;
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            margin: 10px 5px;
            font-size: 14px;
            font-weight: 600;
            transition: all 0.3s;
        }
        .download-btn:hover {
            background: #1c65e0;
            transform: translateY(-2px);
        }
        .retry-btn {
            padding: 12px 24px;
            background: #6c757d;
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            margin: 10px 5px;
            font-size: 14px;
            font-weight: 600;
            transition: all 0.3s;
        }
        .retry-btn:hover {
            background: #5a6268;
            transform: translateY(-2px);
        }
        .prompt-info {
            font-size: 14px;
            color: #666;
            margin: 15px 0;
            text-align: left;
            background: #f8f9fa;
            padding: 12px;
            border-radius: 8px;
            border-left: 4px solid #2575fc;
        }
        .prompt-info strong {
            color: #333;
        }

        /* 配置信息样式 */
        .config-info {
            background: rgba(255, 255, 255, 0.1);
            padding: 15px;
            border-radius: 10px;
            margin: 20px 0;
            color: white;
        }
        .config-info h3 {
            margin-bottom: 10px;
            font-size: 16px;
        }
        .config-info pre {
            background: rgba(0, 0, 0, 0.2);
            padding: 10px;
            border-radius: 5px;
            overflow-x: auto;
            font-size: 13px;
        }

        /* 示例样式 */
        .examples {
            margin-top: 20px;
        }
        .examples h3 {
            margin-bottom: 12px;
            color: #444;
            font-size: 16px;
        }
        .example-item {
            background: #f8faff;
            border-left: 4px solid #2575fc;
            padding: 10px 12px;
            margin-bottom: 8px;
            border-radius: 0 6px 6px 0;
            cursor: pointer;
            transition: all 0.2s;
            font-size: 14px;
        }
        .example-item:hover {
            background: #eef4ff;
            transform: translateX(5px);
        }

        @media (max-width: 768px) {
            .header h1 {
                font-size: 32px;
            }
            .header p {
                font-size: 16px;
            }
            .download-btn, .retry-btn {
                width: 100%;
                margin: 5px 0;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <div class="header">
        <h1>AI文生图测试</h1>
        <p>输入文本描述,AI将生成对应的图片</p>
    </div>

    <!-- 配置信息展示 -->
    <div class="config-info">
        <h3>当前配置</h3>
        <pre id="config-display"></pre>
    </div>

    <div class="generator-card">
        <div class="card-header">
            <h2>文生图生成器</h2>
            <p>输入文本描述,AI将根据描述生成图片</p>
        </div>
        <div class="card-content">
            <label for="image-input" class="input-label">图片描述</label>
            <p class="input-hint">详细描述您想要生成的图片内容、风格和元素</p>
            <textarea id="image-input" class="text-input" placeholder="例如:一只可爱的卡通猫坐在窗台上,阳光透过窗户,周围有绿植,风格温暖明亮"></textarea>
            <button id="generate-image" class="btn">生成图片</button>
            <div id="image-result" class="result-container">
                <!-- 结果将在这里显示 -->
            </div>

            <div class="examples">
                <h3>示例提示</h3>
                <div class="example-item" data-target="image-input">一只在森林中奔跑的红色狐狸,阳光透过树叶,神秘梦幻的风格</div>
                <div class="example-item" data-target="image-input">未来城市夜景,霓虹灯光,飞行汽车,赛博朋克风格</div>
                <div class="example-item" data-target="image-input">宁静的海滩日落,金色沙滩,粉色天空,帆船在远处,油画风格</div>
            </div>
        </div>
    </div>

    <div class="footer">
        <p>AI文生图测试 &copy; 2025</p>
    </div>
</div>

<script>
    // 配置信息
    const CONFIG = {
        PROXY_URL: "http://localhost:3000",
        TEXT_MODEL: "qwen-turbo",
        IMAGE_MODEL: "wan2.5-t2i-preview"
    };

    // 状态管理
    const state = {
        isGenerating: false,
        lastGeneratedImage: null
    };

    // 优化提示词的模板
    const PROMPT_TEMPLATE = (userInput) =>
        `Generate a high-quality image with the following description: ${userInput}.
        Style: professional, visually appealing, well-composed, with good lighting and detail.
        The image should be suitable for digital use and display.`;

    // 1. 优化提示词
    async function optimizePrompt(userInput) {
        try {
            console.log(`优化提示词:`, userInput);

            // 如果用户输入的是中文,使用模板优化
            if (/[\u4e00-\u9fa5]/.test(userInput)) {
                const optimized = PROMPT_TEMPLATE(userInput);
                console.log("优化后的提示词:", optimized);
                return optimized;
            }

            return userInput;

        } catch (error) {
            console.error("提示词优化失败:", error);
            return userInput;
        }
    }

    // 2. 检查任务状态
    async function checkTaskStatus(taskId) {
        try {
            const response = await fetch(`${CONFIG.PROXY_URL}/api/tasks/${taskId}`, {
                method: "GET",
            });

            if (!response.ok) {
                const errorData = await response.json();
                throw new Error(`查询失败: ${response.status} - ${errorData.error || '未知错误'}`);
            }

            const data = await response.json();

            if (data.output?.task_status === 'SUCCEEDED') {
                // 任务完成,返回图片URL
                return {
                    status: 'success',
                    imageUrl: data.output.results?.[0]?.url,
                    taskData: data
                };
            } else if (data.output?.task_status === 'PENDING' || data.output?.task_status === 'RUNNING') {
                // 任务仍在处理中
                return {
                    status: 'pending',
                    taskStatus: data.output.task_status,
                    taskData: data
                };
            } else if (data.output?.task_status === 'FAILED') {
                // 任务失败
                throw new Error(`任务失败: ${data.output?.message || '未知错误'}`);
            } else {
                // 未知状态
                throw new Error(`未知任务状态: ${data.output?.task_status}`);
            }
        } catch (error) {
            console.error('任务状态查询错误:', error);
            throw error;
        }
    }

    // 3. 轮询检查任务状态
    async function pollTaskStatus(taskId, resultContainer, optimizedPrompt) {
        const maxAttempts = 30; // 最多尝试30次
        const interval = 3000; // 3秒检查一次

        for (let attempt = 0; attempt < maxAttempts; attempt++) {
            try {
                const result = await checkTaskStatus(taskId);

                if (result.status === 'success') {
                    // 任务完成,显示图片
                    state.lastGeneratedImage = result.imageUrl;
                    const downloadId = `download_${Date.now()}`;
                    const retryId = `retry_${Date.now()}`;

                    resultContainer.innerHTML = `
                        <div class="success">🎉 生成成功!</div>
                        <img src="${result.imageUrl}" alt="AI生成图片" class="result-img">
                        <div class="prompt-info">
                            <strong>优化后提示词:</strong><br>
                            ${optimizedPrompt.substring(0, 150)}${optimizedPrompt.length > 150 ? '...' : ''}
                        </div>
                        <div>
                            <button id="${downloadId}" class="download-btn">
                                📥 下载图片
                            </button>
                            <button id="${retryId}" class="retry-btn">
                                🔄 重新生成
                            </button>
                        </div>
                    `;

                    // 重新绑定下载按钮事件
                    document.getElementById(downloadId).addEventListener('click', () => {
                        downloadImage(result.imageUrl, `ai_image_${Date.now()}`);
                    });

                    // 重新绑定重试按钮事件
                    document.getElementById(retryId).addEventListener('click', retryGeneration);

                    return;
                } else if (result.status === 'pending') {
                    // 仍在处理中
                    const status = result.taskStatus || '处理中';
                    const progress = Math.min(100, Math.floor((attempt / maxAttempts) * 100));
                    resultContainer.innerHTML = `<div class="loading">⏳ 图片生成中... (${status}) 进度: ${progress}% (${attempt + 1}/${maxAttempts})</div>`;

                    // 继续等待
                    await new Promise(resolve => setTimeout(resolve, interval));
                }
            } catch (error) {
                console.error('轮询错误:', error);
                resultContainer.innerHTML = `
                    <div class="error">❌ 任务处理失败</div>
                    <div style="color:#666; margin:10px 0; font-size:14px;">${error.message}</div>
                    <button class="retry-btn" onclick="retryGeneration()">🔄 重新尝试</button>
                `;
                return;
            }
        }

        // 超时处理
        resultContainer.innerHTML = `
            <div class="error">⏰ 生成超时,请稍后重试</div>
            <div class="prompt-info">
                <strong>任务ID:</strong> ${taskId}<br>
                <strong>优化提示词:</strong> ${optimizedPrompt.substring(0, 100)}...
            </div>
            <button class="retry-btn" onclick="retryGeneration()">🔄 重新尝试</button>
        `;
    }

    // 4. 生成图片
    async function generateImage() {
        if (state.isGenerating) {
            alert("请等待当前生成完成");
            return;
        }

        const userInput = document.getElementById('image-input').value.trim();
        if (!userInput) {
            alert("请输入图片描述!");
            return;
        }

        // 更新UI状态
        state.isGenerating = true;
        const button = document.getElementById('generate-image');
        const resultContainer = document.getElementById('image-result');
        const originalText = button.textContent;
        button.textContent = "生成中...";
        button.disabled = true;

        resultContainer.innerHTML = '<div class="loading">AI正在创作中,这可能需要10-30秒...</div>';

        try {
            // 优化提示词
            const optimizedPrompt = await optimizePrompt(userInput);

            console.log(`生成图片,优化后提示词:`, optimizedPrompt);
            const requestBody = {
                model: CONFIG.IMAGE_MODEL,
                prompt: optimizedPrompt,
                parameters: {
                    size: "1024 * 1024",
                    n: 1
                }
            };

            console.log(`生成图片请求体:`, requestBody);

            // 调用图片生成接口
            const response = await fetch(`${CONFIG.PROXY_URL}/api/image`, {
                method: "POST",
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify(requestBody)
            });

            if (!response.ok) {
                const errorText = await response.text();
                console.error("请求失败响应:", errorText);
                throw new Error(`图片生成失败:${response.status}`);
            }

            const data = await response.json();
            console.log(`图片生成响应:`, data);

            if (data.output?.task_id) {
                // 获取任务ID,开始轮询
                const taskId = data.output.task_id;
                console.log(`任务已提交,任务ID: ${taskId}`);

                // 开始轮询任务状态
                await pollTaskStatus(taskId, resultContainer, optimizedPrompt);

            } else if (data.output?.results?.[0]?.url) {
                // 如果直接返回图片URL(同步模式)
                const imageUrl = data.output.results[0].url;
                state.lastGeneratedImage = imageUrl;

                resultContainer.innerHTML = `
                    <div class="success">🎉 生成成功!</div>
                    <img src="${imageUrl}" alt="AI生成图片" class="result-img">
                    <div class="prompt-info">
                        <strong>优化后提示词:</strong><br>
                        ${optimizedPrompt.substring(0, 150)}${optimizedPrompt.length > 150 ? '...' : ''}
                    </div>
                    <div>
                        <button id="download-btn-latest" class="download-btn">
                            📥 下载图片
                        </button>
                        <button id="retry-btn-latest" class="retry-btn">
                            🔄 重新生成
                        </button>
                    </div>
                `;

                // 绑定下载按钮事件
                document.getElementById('download-btn-latest').addEventListener('click', () => {
                    downloadImage(imageUrl, `ai_image_${Date.now()}`);
                });

                // 绑定重试按钮事件
                document.getElementById('retry-btn-latest').addEventListener('click', retryGeneration);
            } else {
                throw new Error("未获取到图片URL或任务ID");
            }

        } catch (error) {
            console.error(`图片生成失败:`, error);

            let errorMessage = error.message;
            if (errorMessage.includes("Failed to fetch")) {
                errorMessage = "网络连接失败。请检查:\n1. 代理服务器是否启动\n2. 网络连接是否正常\n3. 端口号是否正确";
            }

            resultContainer.innerHTML = `
                <div class="error">❌ 生成失败</div>
                <div style="color:#666; margin:10px 0; font-size:14px; white-space: pre-line;">
                    ${errorMessage}
                </div>
                <button class="retry-btn" onclick="retryGeneration()">
                    🔄 重新尝试
                </button>
            `;

        } finally {
            // 恢复状态
            state.isGenerating = false;
            button.textContent = originalText;
            button.disabled = false;
        }
    }

    // 5. 重新生成
    async function retryGeneration() {
        await generateImage();
    }

    // 6. 下载图片 - 修复版
    async function downloadImage(imageUrl, filename) {
        try {
            // 显示下载提示
            alert('开始下载图片,请稍候...');

            // 使用fetch获取图片数据
            const response = await fetch(imageUrl);

            if (!response.ok) {
                throw new Error(`下载失败: ${response.status}`);
            }

            // 转换为blob
            const blob = await response.blob();

            // 创建下载链接
            const url = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = url;
            link.download = filename + '.png';

            // 添加到DOM并点击
            document.body.appendChild(link);
            link.click();

            // 清理
            document.body.removeChild(link);
            window.URL.revokeObjectURL(url);

            // 显示成功提示
            setTimeout(() => {
                alert('图片下载成功!请查看您的下载文件夹。');
            }, 100);

        } catch (error) {
            console.error('下载失败:', error);

            // 如果fetch失败,尝试使用备用方法
            try {
                alert('直接下载失败,尝试备用方法...');

                // 备用方法:在新窗口中打开图片,让用户手动保存
                const newWindow = window.open(imageUrl, '_blank');
                if (!newWindow) {
                    alert('请允许弹出窗口,然后右键图片选择"图片另存为..."');
                }
            } catch (fallbackError) {
                console.error('备用方法也失败:', fallbackError);
                alert('下载失败,请右键图片选择"图片另存为..."');
            }
        }
    }

    // 7. 初始化
    document.addEventListener('DOMContentLoaded', function() {
        // 显示配置信息
        document.getElementById('config-display').textContent =
            `代理地址: ${CONFIG.PROXY_URL}\n` +
            `文本模型: ${CONFIG.TEXT_MODEL}\n` +
            `图片模型: ${CONFIG.IMAGE_MODEL}\n` +
            `图片尺寸: 1024x1024`;

        // 绑定示例点击
        document.querySelectorAll('.example-item').forEach(item => {
            item.addEventListener('click', function() {
                const targetId = this.getAttribute('data-target');
                const targetInput = document.getElementById(targetId);
                if (targetInput) {
                    targetInput.value = this.textContent;
                    targetInput.focus();
                }
            });
        });

        // 绑定生成按钮
        document.getElementById('generate-image').addEventListener('click', generateImage);

        // 允许按Enter键生成图片(在文本框中)
        document.getElementById('image-input').addEventListener('keydown', function(event) {
            if (event.ctrlKey && event.key === 'Enter') {
                event.preventDefault();
                generateImage();
            }
        });

        console.log('前端配置:', CONFIG);
    });
</script>
</body>
</html>

2.2 创建server.js

const express = require('express');
const cors = require('cors');
const axios = require('axios');

const app = express();

// 1. 基础配置
app.use(cors());
app.use(express.json({ strict: true }));

// 2. 核心
const API_KEY = 'sk-xxx';

// 3. 创建安全的请求头
function createHeaders(isImage = false) {
    const headers = {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_KEY}`
    };
    if (isImage) {
        headers['X-DashScope-Async'] = 'enable';
    }
    return headers;
}

// 4. 文本生成接口
app.post('/api/text', async (req, res) => {
    try {
        console.log('📝 文本生成请求');
        const headers = createHeaders(false);
        const response = await axios.post(
            'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation',
            req.body,
            { headers, timeout: 30000 }
        );
        res.json(response.data);
    } catch (error) {
        console.error('文本生成错误:', error.message);
        res.status(error.response?.status || 500).json({
            error: error.message,
            details: error.response?.data
        });
    }
});

// 5. 图片生成接口
app.post('/api/image', async (req, res) => {
    try {
        console.log('🎨 图片生成请求');
        const headers = createHeaders(true);

        // 构造请求体,确保包含必要参数
        const requestBody = {
            model: req.body.model || "wan2.5-t2i-preview", // 默认模型
            input: {
                prompt: req.body.prompt
            },
            parameters: req.body.parameters || {
                size: "1024*1024",
                n: 1
            }
        };

        console.log('📤 发送图片生成请求:', JSON.stringify(requestBody, null, 2));

        const response = await axios.post(
            'https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis',
            requestBody,
            { headers, timeout: 60000 }
        );

        console.log('📥 图片生成响应:', JSON.stringify(response.data, null, 2));
        res.json(response.data);

    } catch (error) {
        console.error('❌ 图片生成错误:', error.message);
        if (error.response) {
            console.error('错误响应:', error.response.data);
        }
        res.status(error.response?.status || 500).json({
            error: error.message,
            details: error.response?.data
        });
    }
});

// 6. 任务状态查询接口
app.get('/api/tasks/:taskId', async (req, res) => {
    try {
        const { taskId } = req.params;
        console.log(`🔍 查询任务状态: ${taskId}`);

        const headers = createHeaders(false);

        const response = await axios.get(
            `https://dashscope.aliyuncs.com/api/v1/tasks/${taskId}`,
            { headers, timeout: 10000 }
        );

        console.log('📋 任务状态响应:', response.data);
        res.json(response.data);

    } catch (error) {
        console.error('❌ 任务查询错误:', error.message);
        res.status(error.response?.status || 500).json({
            error: error.message,
            details: error.response?.data
        });
    }
});

// 7. 健康检查
app.get('/api/health', (req, res) => {
    res.json({
        status: 'ok',
        apiKey: {
            length: API_KEY.length,
            valid: API_KEY.startsWith('sk-') && API_KEY.length === 35,
            authHeader: `Bearer ${API_KEY.substring(0, 10)}...`
        }
    });
});

// 8. 测试接口
app.post('/api/test', async (req, res) => {
    try {
        const headers = createHeaders(false);
        const testData = {
            model: "qwen-turbo",
            input: {
                messages: [{ role: "user", content: "你好" }]
            }
        };
        const response = await axios.post(
            'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation',
            testData,
            { headers, timeout: 10000 }
        );
        res.json({ success: true, data: response.data });
    } catch (error) {
        res.status(500).json({
            success: false,
            error: error.message,
            response: error.response?.data
        });
    }
});

// 启动服务器
const PORT = 3000;
app.listen(PORT, () => {
    console.log('\n🚀 代理服务器启动成功');
    console.log(`🌐 健康检查: http://localhost:${PORT}/api/health`);
    console.log(`🧪 测试接口: http://localhost:${PORT}/api/test`);
    console.log(`🎨 图片生成: http://localhost:${PORT}/api/image`);
    console.log(`🔍 任务查询: http://localhost:${PORT}/api/tasks/:taskId`);
});

2.3 运行server.js

PS H:Ai> node server.js

🚀 代理服务器启动成功
🌐 健康检查: http://localhost:3000/api/health
🧪 测试接口: http://localhost:3000/api/test
🎨 图片生成: http://localhost:3000/api/image
🔍 任务查询: http://localhost:3000/api/tasks/:taskId

2.4 运行结果

在这里插入图片描述
在这里插入图片描述
阿里云百炼大模型集成完成

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值