社区驱动的免费 AI 工具、TTS 和 APIs,面向 Twitch 主播
社区驱动的免费 AI 工具、TTS 和 APIs,面向 Twitch 主播

如何在 Streamer.bot 中通过自定义脚本生成 AI 图像

了解如何直接在 Streamer.bot 中为你的 Twitch 直播生成免费的 AI 图像,通过添加自定义的 Execute Code 脚本,无需任何第三方中间件。
本页面由我们积极进取的 AI 实习生为您翻译,方便您使用。它们仍在学习阶段,可能会有少许错误。如需获得最准确的信息,请以英文版本为准。
分步教程 如何在 Streamer.bot 中通过自定义脚本生成 AI 图像

PotatoHotDog 提供一个免费的生成 AI 图像 API,你可以直接通过 Streamer.bot 调用它,无需任何第三方中间件。本指南将向你展示如何在 Streamer.bot 的 Execute Code 子动作中添加一个小型的自定义 C# 脚本,该脚本根据文本提示生成 AI 图像,并将其下载到磁盘。

该脚本只需要你的 PotatoHotDog API 密钥和一个描述你想要生成的图像的提示,它会将下载的图像保存到 Streamer.bot 安装目录下的一个专用文件夹中。

请准备一个 API 密钥

如果你还没有,请从仪表板生成一个 API 密钥并妥善保管,下一步你将需要它。

前往 API 密钥 在 PotatoHotDog 仪表板中生成 API 密钥

先决参数

为了生成 AI 图像,在 Execute Code 子操作运行之前,需要在 Streamer.bot 中指定两个参数。换句话说,这两项需要被指定:

  • 一个 API 密钥。
  • 用于描述你想要生成的图像的提示说明。

这些对应于以下的 Streamer.bot 参数:

  • potatoKey
  • potatoInstructions

你可以在你的操作中通过对 Sub Actions 右键单击来指定参数,然后依次选择 Add、Core、Arguments,最后选择 Set Argument。

在 Streamer.bot 中添加一个 Set Argument 子操作

在 Streamer.bot 中添加执行代码动作

打开 Streamer.bot,进入 Actions 标签页。创建一个新动作,或打开一个已存在的动作,并给它起一个日后你会认出的名字,例如“PotatoHotDog AI Image”。

在已选中的操作下,点击 Sub Actions 下的 Add,然后依次选择 Core,接着选择 Execute C# Code。这将新增一个子操作,您可以粘贴原始 C# 代码,Streamer.bot 将现场编译并运行。

在 Streamer.bot 中添加一个执行 C# 代码的子操作

把下面的脚本粘贴到代码编辑器中。它会读取 potatoKey 和 potatoInstructions 参数,调用我们的 Generate AI Image API 来生成图像并获取其 URL,然后将生成的图像下载到你在 Streamer.bot 安装目录中的名为 temp_potatohotdog_images 的文件夹中。

using System; using System.IO; using System.Net.Http; using Newtonsoft.Json.Linq; public class CPHInline { // Tracks the version of this script for troubleshooting and support. private const string VERSION = "1.0.0"; // Base URL for the endpoint that generates an AI image. private const string BASE_URL_GENERATE = "https://api-generate-image-v1.potatohotdog.com/"; // Tracks the next numbered log argument. private int logIndex = 0; // Reuses one HTTP client for all API requests. private static readonly HttpClient httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; // Adds a log message as a numbered action argument. private void Log(string message) { // Stores the message under a numbered key. CPH.SetArgument($"potatoLog{logIndex}", message); // Advances the log index for the next message. logIndex++; // Keeps the total log count in sync. CPH.SetArgument("potatoLogCount", logIndex); } // Ensures a required action argument exists and is not empty. private bool RequireArgument(string name, out string value) { // Fails when the argument is missing or blank. if (!CPH.TryGetArg(name, out value) || string.IsNullOrWhiteSpace(value)) { value = ""; return false; } return true; } // URL-encodes a value so it can safely be used in a query string. private string EncodeUrlValue(string value) { // Escapes reserved characters for safe use in a URL. return Uri.EscapeDataString(value); } // Performs an HTTP GET request and returns the response body. private string HttpGet(string url) { try { Log($"GET {url}"); // Sends the HTTP request synchronously. HttpResponseMessage response = httpClient.GetAsync(url).GetAwaiter().GetResult(); // Reads the complete response body. string responseBody = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); Log($"HTTP status: {(int)response.StatusCode} {response.ReasonPhrase}"); // Stops when the server returns an unsuccessful status code. if (!response.IsSuccessStatusCode) { Log($"Error: HTTP request failed with status {(int)response.StatusCode} {response.ReasonPhrase}."); // Logs the server error response when available. if (!string.IsNullOrWhiteSpace(responseBody)) { Log($"Error response: {responseBody}"); } return null; } Log($"Received {responseBody.Length} characters."); return responseBody; } catch (Exception exception) { // Logs network, timeout, and other HTTP-related exceptions. Log($"Error: HTTP request failed: {exception.Message}"); return null; } } // Downloads a file from a URL and saves it to disk. private bool DownloadFile(string url, string destinationPath) { try { Log($"Downloading image from \"{url}\"."); Log($"Saving image to \"{destinationPath}\"."); // Sends the image download request. HttpResponseMessage response = httpClient.GetAsync(url).GetAwaiter().GetResult(); Log($"Image download HTTP status: {(int)response.StatusCode} {response.ReasonPhrase}"); // Reads the complete image response into memory. byte[] fileData = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(); // Stops when the image server returns an unsuccessful status. if (!response.IsSuccessStatusCode) { Log($"Error: Image download failed with status {(int)response.StatusCode} {response.ReasonPhrase}."); return false; } // Rejects an empty image response. if (fileData == null || fileData.Length == 0) { Log("Error: The downloaded image file is empty."); return false; } // Writes the downloaded image bytes to the destination file. File.WriteAllBytes(destinationPath, fileData); Log($"Downloaded {fileData.Length} image bytes."); // Confirms that the image file now exists on disk. if (!File.Exists(destinationPath)) { Log("Error: The image download completed, but the file does not exist on disk."); return false; } // Reports the final file size from disk. FileInfo fileInfo = new FileInfo(destinationPath); Log($"Image file saved successfully. File size: {fileInfo.Length} bytes."); return true; } catch (Exception exception) { // Logs download, filesystem, and permission errors. Log($"Error: Could not download the image file: {exception.Message}"); return false; } } // Extracts a required string value from a JSON response. private bool TryGetJsonString(string json, string propertyName, out string value) { value = ""; try { // Parses the response body as a JSON object. JObject jsonObject = JObject.Parse(json); // Retrieves the requested JSON property. JToken property = jsonObject[propertyName]; if (property == null) { Log($"Error: JSON response does not contain \"{propertyName}\"."); return false; } value = property.ToString(); // Rejects empty JSON string values. if (string.IsNullOrWhiteSpace(value)) { Log($"Error: JSON property \"{propertyName}\" is empty."); value = ""; return false; } return true; } catch (Exception exception) { // Logs malformed JSON and property conversion errors. Log($"Error: Could not parse JSON property \"{propertyName}\": {exception.Message}"); return false; } } // Creates and returns the dedicated PotatoImage folder. private string GetImageFolder() { // Uses Streamer.bot's application directory instead of the process working directory. string streamerBotFolder = AppDomain.CurrentDomain.BaseDirectory; // Places generated image files inside a dedicated subfolder. string imageFolder = Path.Combine(streamerBotFolder, "temp_potatohotdog_images"); Log($"Streamer.bot folder: \"{streamerBotFolder}\"."); Log($"Image folder: \"{imageFolder}\"."); // Creates the image folder if it does not already exist. if (!Directory.Exists(imageFolder)) { Log("Image folder does not exist. Creating it..."); Directory.CreateDirectory(imageFolder); Log("Image folder created."); } else { Log("Image folder already exists."); } return imageFolder; } // Runs the main PotatoHotdog AI image action. public bool Execute() { // Resets log numbering for this execution. logIndex = 0; CPH.SetArgument("potatoLogCount", 0); Log("Starting script..."); // Logs the script version so runs can be tracked over time. Log($"Version: {VERSION}"); // Retrieves the PotatoHotdog API key. if (!RequireArgument("potatoKey", out string potatoKey)) { Log("Error: potatoKey variable is missing. Please login to potatohotdog.com, generate an API key, create a set variable action and save the variable \"potatoKey\" with your key."); return false; } // Retrieves the prompt instructions describing the image to generate. if (!RequireArgument("potatoInstructions", out string potatoInstructions)) { Log("Error: potatoInstructions variable is missing. Create a set variable action and save the variable \"potatoInstructions\" with a description of the image you want generated."); return false; } // Logs the non-secret input values. Log("potatoKey was provided."); Log($"potatoInstructions=\"{potatoInstructions}\""); // Builds the API URL used to generate the AI image. string generateUrl = BASE_URL_GENERATE + "?key=" + EncodeUrlValue(potatoKey) + "&instructions=" + EncodeUrlValue(potatoInstructions); // Requests generation of the AI image. string generateJson = HttpGet(generateUrl); if (generateJson == null) { Log("Error: Failed to generate the AI image."); return false; } Log($"Generate response: {generateJson}"); // Extracts the generated item's ID, reused below as the local filename. if (!TryGetJsonString(generateJson, "itemID", out string itemID)) { Log("Error: Could not retrieve itemID from the generate response."); return false; } Log($"itemID=\"{itemID}\""); // Logs the generation duration when present, purely for troubleshooting. if (TryGetJsonString(generateJson, "duration", out string duration)) { Log($"duration={duration} second(s)"); } // Extracts the generated image URL from the response. if (!TryGetJsonString(generateJson, "imageURL", out string imageURL)) { Log("Error: Could not retrieve imageURL from the generate response."); return false; } Log($"imageURL=\"{imageURL}\""); string imageFolder; try { // Resolves and creates the dedicated PotatoImage directory. imageFolder = GetImageFolder(); } catch (Exception exception) { Log($"Error: Could not create or access the image folder: {exception.Message}"); return false; } // Reuses the item's own ID as the local filename instead of minting a new one. string imageFileName = $"{itemID}.png"; // Combines the image folder and unique filename. string imageFilePath = Path.Combine(imageFolder, imageFileName); Log($"Generated image filename: \"{imageFileName}\"."); Log($"Local image path: \"{imageFilePath}\"."); // Downloads the generated image file to the PotatoImage folder. if (!DownloadFile(imageURL, imageFilePath)) { Log("Error: Failed to download the generated AI image."); return false; } // Stores the remote image URL as a final action argument. CPH.SetArgument("potatoGeneratedImageURL", imageURL); // Stores the absolute local file path as a final action argument. CPH.SetArgument("potatoGeneratedImageFile", imageFilePath); Log($"potatoGeneratedImageURL=\"{imageURL}\""); Log($"potatoGeneratedImageFile=\"{imageFilePath}\""); Log("Finished."); return true; } }

粘贴脚本后,记得点击 Find Refs 和 Compile,确保它能成功编译。保存该操作,然后手动触发它,或将其绑定到一个命令或频道点数奖励,以测试图像是否正确生成。

将脚本粘贴到 Streamer.bot 中并进行编译

查看已下载的图片

一旦 Action 运行完成,您可以通过 Action History 查看 Action 变量,以确认一切按预期工作。

在这里,您将找到生成的图像在磁盘上保存的本地路径,该路径位于 Streamer.bot 安装目录中的 temp_potatohotdog_images 文件夹内。

在操作历史中查看生成的图像变量

打开该文件夹以直接查看已下载的图片。

通过 Streamer.bot 的 Action History 查看 Action 变量

故障排除

如果脚本没有按预期工作,排查的最佳方法是查看操作日志。

你可以通过在 Action History 中查看你的 Action 变量来完成此操作。

通过 Streamer.bot 的 Action History 查看 Action 变量

本指南首次发布于 2026-07-19,最近一次修改时间为 2026-07-19。

其他类似指南

以下是一些你可能会觉得有用的其他操作指南。

如何将 Streamer.bot 连接到人工智能
如何将 Streamer.bot 连接到人工智能
了解如何在 Streamer.bot 中为你的 Twitch 串流生成免费的 AI(LLM)响应,使用 Fetch URL 子动作和 PotatoHotDog 生成 AI 响应 API,无需自定义脚本。
阅读指南
如何在 Streamer.bot 中使用动态浏览器源播放免费 TTS 音频
如何在 Streamer.bot 中使用动态浏览器源播放免费 TTS 音频
了解如何在 Streamer.bot 中为你的 Twitch 直播播放免费的 AI TTS (Text-to-Speech) 音频,使用 Dynamic Browser Source 和一个简单的 Fetch URL webhook 请求,无需自定义脚本。
阅读指南
如何在 Streamer.bot 中使用自定义脚本播放免费 TTS 音频
如何在 Streamer.bot 中使用自定义脚本播放免费 TTS 音频
了解如何在 Streamer.bot 中直接为你的 Twitch 直播播放免费 AI TTS(文本转语音)音频,只需添加一个自定义 Execute Code 脚本,无需 Speaker.bot。
阅读指南