admin 发表于 2024-8-27 17:10:22

免费绘画,用不完!部署 CF Worker,支持 API,多模型切换。

【第一弹】用不完,根本用不完,部署cf worker无限免费绘画,可Api,支持多模型切换 - 常规话题 / 人工智能 - LINUX DO
支持/v1/chat/completions,/v1/models接口
需要cloudflare账号,申请账号token,这一步可以百度或者复制以下代码,部署到cloudflare,记得把account_id,token改为你自己的
部署到CF的worker.js中
//本项目授权api_key,防止被恶意调用(填写到one-api,new-api中的渠道密钥)
const API_KEY = "sk-1234567890";
//cloudflare账号列表,每次请求都会随机从列表里取一个账号
const CF_ACCOUNT_LIST = [
{ account_id: "xxxxxx", token: "xxxxxx" }
];
//是否开启提示词翻译、优化功能
const CF_IS_TRANSLATE = true;
//提示词翻译、优化模型
const CF_TRANSLATE_MODEL = "@cf/qwen/qwen1.5-14b-chat-awq";
//模型映射,设置客户端可用的模型。one-api,new-api在添加渠道时可使用“获取模型列表”功能,一键添加模型
const CUSTOMER_MODEL_MAP = {
"dreamshaper-8": "@cf/lykon/dreamshaper-8-lcm",
"stable-diffusion-xl-base-cf": "@cf/stabilityai/stable-diffusion-xl-base-1.0",
"stable-diffusion-xl-lightning-cf": "@cf/bytedance/stable-diffusion-xl-lightning"
};
async function handleRequest(request) {
try {
    if (request.method === "OPTIONS") {
      return new Response("", {
      status: 204,
      headers: {
          'Access-Control-Allow-Origin': '*',
          "Access-Control-Allow-Headers": '*'
      }
      });
    }
    if (/^(https?:\/\/[^\/]*?)\/file\//i.test(request.url)) {
      if (request.headers.get("if-modified-since")) {
      return new Response("", {
          status: 304,
          headers: {
            'Access-Control-Allow-Origin': '*',
            "Access-Control-Allow-Headers": '*',
            "Last-Modified": request.headers.get("If-Modified-Since")
          }
      });
      }
      const img = await fetch(request.url.replace(/^(https?:\/\/[^\/]*?)\//, "https://telegra.ph/"));
      return new Response(img.body, {
      status: img.status,
      headers: {
          "content-type": img.headers.get("content-type"),
          'Access-Control-Allow-Origin': '*',
          "Access-Control-Allow-Headers": '*',
          "Last-Modified": (new Date()).toUTCString(),
          "Cache-Control": "public, max-age=31536000"
      }
      });
    }
    const authHeader = request.headers.get("Authorization");
    if (!authHeader || !authHeader.startsWith("Bearer ") || authHeader.split(" ") !== API_KEY) {
      return new Response("Unauthorized", { status: 401 });
    }
    if (request.url.endsWith("/v1/models")) {
      const arrs = [];
      Object.keys(CUSTOMER_MODEL_MAP).map(element => arrs.push({ id: element, object: "model" }))
      const response = {
      data: arrs,
      success: true
      };
      return new Response(JSON.stringify(response), {
      headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Headers': '*'
      }
      });
    }
    if (request.method !== "POST") {
      return new Response("Only POST requests are allowed", {
      status: 405,
      });
    }
    if (!request.url.endsWith("/v1/chat/completions")) {
      return new Response("Not Found", {
      status: 404,
      });
    }
    const data = await request.json();
    const messages = data.messages || [];
    const model = CUSTOMER_MODEL_MAP || CUSTOMER_MODEL_MAP["stable-diffusion-xl-lightning"];
    const stream = data.stream || false;
    const userMessage = messages.reverse().find((msg) => msg.role === "user")?.content;
    if (!userMessage) {
      return new Response(JSON.stringify({ error: "未找到用户消息" }), {
      status: 400,
      headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Headers': '*'
      }
      });
    }
    const originalPrompt = userMessage;
    const translatedPrompt = CF_IS_TRANSLATE ? await getPrompt(originalPrompt) : originalPrompt;
    const imageUrl = request.url.match(/^(https?:\/\/[^\/]*?)\//) + await generateImageByText(model, translatedPrompt);
    if (stream) {
      return handleStreamResponse(originalPrompt, translatedPrompt, "1024x1024", model, imageUrl);
    } else {
      return handleNonStreamResponse(originalPrompt, translatedPrompt, "1024x1024", model, imageUrl);
    }
} catch (error) {
    return new Response("Internal Server Error: " + error.message, {
      status: 500,
      headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Headers': '*'
      }
    });
}
}
async function getPrompt(prompt) {
const requestBodyJson = {
    messages: [
      {
      role: "system",
      content: `作为 Stable Diffusion Prompt 提示词专家,您将从关键词中创建提示,通常来自 Danbooru 等数据库。
      提示通常描述图像,使用常见词汇,按重要性排列,并用逗号分隔。避免使用"-"或".",但可以接受空格和自然语言。避免词汇重复。
      为了强调关键词,请将其放在括号中以增加其权重。例如,"(flowers)"将'flowers'的权重增加1.1倍,而"(((flowers)))"将其增加1.331倍。使用"(flowers:1.5)"将'flowers'的权重增加1.5倍。只为重要的标签增加权重。
      提示包括三个部分:**前缀**(质量标签+风格词+效果器)+ **主题**(图像的主要焦点)+ **场景**(背景、环境)。
      *   前缀影响图像质量。像"masterpiece"、"best quality"、"4k"这样的标签可以提高图像的细节。像"illustration"、"lensflare"这样的风格词定义图像的风格。像"bestlighting"、"lensflare"、"depthoffield"这样的效果器会影响光照和深度。
      *   主题是图像的主要焦点,如角色或场景。对主题进行详细描述可以确保图像丰富而详细。增加主题的权重以增强其清晰度。对于角色,描述面部、头发、身体、服装、姿势等特征。
      *   场景描述环境。没有场景,图像的背景是平淡的,主题显得过大。某些主题本身包含场景(例如建筑物、风景)。像"花草草地"、"阳光"、"河流"这样的环境词可以丰富场景。你的任务是设计图像生成的提示。请按照以下步骤进行操作:
      1.我会发送给您一个图像场景。需要你生成详细的图像描述
      2.图像描述必须是英文,输出为Positive Prompt。
      示例:
      我发送:二战时期的护士。
      您回复只回复:
      A WWII-era nurse in a German uniform, holding a wine bottle and stethoscope, sitting at a table in white attire, with a table in the background, masterpiece, best quality, 4k, illustration style, best lighting, depth of field, detailed character, detailed environment.`
      },
      {
      role: "user",
      content: prompt
      }
    ]
};
const response = await postRequest(CF_TRANSLATE_MODEL, requestBodyJson);
if (!response.ok) {
    return prompt;
}
const jsonResponse = await response.json();
const res = jsonResponse.result.response;
return res;
}
async function generateImageByText(model, prompt) {
const jsonBody = { prompt: prompt, num_steps: 20, guidance: 7.5, strength: 1, width: 1024, height: 1024 };
const response = await postRequest(model, jsonBody);
const imageUrl = await uploadImage(response);
return imageUrl;
}
async function uploadImage(response) {
const imageBlob = await response.blob();
const formData = new FormData();
formData.append("file", imageBlob, "image.jpg");
const uploadResponse = await fetch("https://telegra.ph/upload", {
    method: 'POST',
    body: formData,
});
if (!uploadResponse.ok) {
    throw new Error("Failed to upload image");
}
const uploadResult = await uploadResponse.json();
const imageUrl = uploadResult.src;
return imageUrl;
}
function handleStreamResponse(originalPrompt, translatedPrompt, size, model, imageUrl) {
const uniqueId = `chatcmpl-${Date.now()}`;
const createdTimestamp = Math.floor(Date.now() / 1000);
const systemFingerprint = "fp_" + Math.random().toString(36).substr(2, 9);
const content = `
页: [1]
查看完整版本: 免费绘画,用不完!部署 CF Worker,支持 API,多模型切换。