RestApiBinder.cs 클래스입니다
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
public class RestApiBinder
{
public async Awaitable<DownloadHandler> HttpAsync(string url, string methodCapital, Dictionary<string, string> headers, string body)
{
if (body != null)
{
byte[] bodyData = Encoding.UTF8.GetBytes(body);
return await HttpByteAsync(url, methodCapital, headers, bodyData);
}
else
{
return await HttpByteAsync(url, methodCapital, headers, null);
}
}
public async Awaitable<DownloadHandler> HttpByteAsync(string url, string methodCapital, Dictionary<string, string> headers, byte[] body)
{
UnityWebRequest request = new UnityWebRequest(url, methodCapital, new DownloadHandlerBuffer(), new UploadHandlerRaw(body));
if (headers != null)
{
foreach (var header in headers)
{
request.SetRequestHeader(header.Key, header.Value);
}
}
await request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
{
Debug.LogError($"Error {request.responseCode}: {request.error}");
return null;
}
return request.downloadHandler;
}
}
Test.cs 클래스입니다
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using UnityEngine.Video;
using Newtonsoft.Json.Linq;
public class Test : MonoBehaviour
{
#region APIKey
const string GEMINI_API_KEY = "YOUR_GEMINI_API_KEY";
const string PIXABAY_API_KEY = "YOUR_PIXABAY_API_KEY";
#endregion
RestApiBinder restApiBinder = new();
[SerializeField] Texture2D sampleTexture;
[SerializeField] RawImage rawImage;
[SerializeField] VideoPlayer videoPlayer;
[ContextMenu("GetGeminiText")]
async Awaitable GetGeminiText()
{
string url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent";
var headers = new Dictionary<string, string>
{
{ "x-goog-api-key", GEMINI_API_KEY },
{ "Content-Type", "application/json" }
};
string myQuestion = "한국의 수도는 뭐야?";
string body = $@"{{
""contents"": [
{{
""parts"": [
{{
""text"": ""{myQuestion}""
}}
]
}}
]
}}";
DownloadHandler downloadHandler = await restApiBinder.HttpAsync(url, "POST", headers, body);
JObject json = JObject.Parse(downloadHandler.text);
string responseText = json["candidates"][0]["content"]["parts"][0]["text"].ToString();
print(responseText);
}
[ContextMenu("GetGeminiMultimodal")]
async Awaitable GetGeminiMultimodal()
{
string url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent";
var headers = new Dictionary<string, string>
{
{ "x-goog-api-key", GEMINI_API_KEY },
{ "Content-Type", "application/json" }
};
Texture2D uncompressTexture = UncompressTexture2D(sampleTexture);
string base64Image = System.Convert.ToBase64String(uncompressTexture.EncodeToJPG());
string body = $@"{{
""contents"": [
{{
""parts"": [
{{
""text"": ""이 그림에 대해 설명해줘.""
}},
{{
""inline_data"": {{
""mime_type"": ""image/jpeg"",
""data"": ""{base64Image}""
}}
}}
]
}}
]
}}";
DownloadHandler downloadHandler = await restApiBinder.HttpAsync(url, "POST", headers, body);
JObject json = JObject.Parse(downloadHandler.text);
string responseText = json["candidates"][0]["content"]["parts"][0]["text"].ToString();
print(responseText);
}
[ContextMenu("GetGeminiChat")]
async Awaitable GetGeminiChat()
{
string url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent";
var headers = new Dictionary<string, string>
{
{ "x-goog-api-key", GEMINI_API_KEY },
{ "Content-Type", "application/json" }
};
string body = @"{
""contents"": [
{
""role"": ""user"",
""parts"": [
{
""text"": ""Hello""
}
]
},
{
""role"": ""model"",
""parts"": [
{
""text"": ""Great to meet you. What would you like to know?""
}
]
},
{
""role"": ""user"",
""parts"": [
{
""text"": ""I have two dogs in my house. How many paws are in my house?""
}
]
}
]
}";
DownloadHandler downloadHandler = await restApiBinder.HttpAsync(url, "POST", headers, body);
JObject json = JObject.Parse(downloadHandler.text);
string responseText = json["candidates"][0]["content"]["parts"][0]["text"].ToString();
print(responseText);
}
[ContextMenu("GetGeminiAudio")]
async Awaitable GetGeminiAudio()
{
string url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-tts:generateContent";
var headers = new Dictionary<string, string>
{
{ "x-goog-api-key", GEMINI_API_KEY },
{ "Content-Type", "application/json" }
};
string body = @"{
""contents"": [{
""parts"":[{
""text"": ""Say cheerfully: Have a wonderful day!""
}]
}],
""generationConfig"": {
""responseModalities"": [""AUDIO""],
""speechConfig"": {
""voiceConfig"": {
""prebuiltVoiceConfig"": {
""voiceName"": ""Zephyr""
}
}
}
},
""model"": ""gemini-2.5-flash-preview-tts"",
}";
DownloadHandler downloadHandler = await restApiBinder.HttpAsync(url, "POST", headers, body);
JObject json = JObject.Parse(downloadHandler.text);
string base64Data = json["candidates"][0]["content"]["parts"][0]["inlineData"]["data"].ToString();
byte[] audioBytes = System.Convert.FromBase64String(base64Data);
string filePath = Path.Combine(Application.persistentDataPath, "gemini_audio.wav");
SaveFilePcmToWav(audioBytes, filePath);
print($"Audio saved: {filePath}");
}
[ContextMenu("GetGeminiImage")]
async Awaitable GetGeminiImage()
{
string url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-preview-image-generation:generateContent";
var headers = new Dictionary<string, string>
{
{ "x-goog-api-key", GEMINI_API_KEY },
{ "Content-Type", "application/json" }
};
string body = @"{
""contents"": [{
""parts"": [
{""text"": ""Hi, can you create a 3d rendered image of a pig with wings and a top hat flying over a happy futuristic scifi city with lots of greenery?""}
]
}],
""generationConfig"":{""responseModalities"":[""TEXT"",""IMAGE""]}
}";
DownloadHandler downloadHandler = await restApiBinder.HttpAsync(url, "POST", headers, body);
JObject json = JObject.Parse(downloadHandler.text);
string base64Data = json["candidates"][0]["content"]["parts"][1]["inlineData"]["data"].ToString();
byte[] imageBytes = System.Convert.FromBase64String(base64Data);
string filePath = Path.Combine(Application.persistentDataPath, "gemini_image.png");
SaveFileImageAndShow(imageBytes, filePath, rawImage);
print($"Image saved: {filePath}");
}
[ContextMenu("GetPixabayImage")]
async Awaitable GetPixabayImage()
{
string url = $"https://pixabay.com/api?key={PIXABAY_API_KEY}&q=yellow+flower";
var headers = new Dictionary<string, string>
{
{ "Content-Type", "application/json" }
};
DownloadHandler downloadHandler = await restApiBinder.HttpAsync(url, "GET", headers, null);
JObject json = JObject.Parse(downloadHandler.text);
string imageUrl = json["hits"][0]["largeImageURL"].ToString();
downloadHandler = await restApiBinder.HttpAsync(imageUrl, "GET", null, null);
string filePath = Path.Combine(Application.persistentDataPath, "pixabay_image.jpg");
SaveFileImageAndShow(downloadHandler.data, filePath, rawImage);
print($"Image saved: {filePath}");
}
[ContextMenu("GetPixabayVideo")]
async Awaitable GetPixabayVideo()
{
string url = $"https://pixabay.com/api/videos?key={PIXABAY_API_KEY}&q=yellow+flower";
var headers = new Dictionary<string, string>
{
{ "Content-Type", "application/json" }
};
DownloadHandler downloadHandler = await restApiBinder.HttpAsync(url, "GET", headers, null);
JObject json = JObject.Parse(downloadHandler.text);
string videoUrl = json["hits"][0]["videos"]["large"]["url"].ToString();
downloadHandler = await restApiBinder.HttpAsync(videoUrl, "GET", null, null);
string filePath = Path.Combine(Application.persistentDataPath, "pixabay_video.mp4");
SaveFileVideoAndShow(downloadHandler.data, filePath, videoPlayer);
print($"Video saved: {filePath}");
}
Texture2D UncompressTexture2D(Texture2D texture)
{
Texture2D readableTexture = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);
readableTexture.SetPixels(texture.GetPixels());
readableTexture.Apply();
return readableTexture;
}
void SaveFilePcmToWav(byte[] pcmData, string filePath, int sampleRate = 24000, int channels = 1, int bitsPerSample = 16)
{
using (var fileStream = new FileStream(filePath, FileMode.Create))
using (var writer = new BinaryWriter(fileStream))
{
writer.Write(Encoding.ASCII.GetBytes("RIFF"));
writer.Write(36 + pcmData.Length);
writer.Write(Encoding.ASCII.GetBytes("WAVE"));
writer.Write(Encoding.ASCII.GetBytes("fmt "));
writer.Write(16);
writer.Write((short)1);
writer.Write((short)channels);
writer.Write(sampleRate);
writer.Write(sampleRate * channels * bitsPerSample / 8);
writer.Write((short)(channels * bitsPerSample / 8));
writer.Write((short)bitsPerSample);
writer.Write(Encoding.ASCII.GetBytes("data"));
writer.Write(pcmData.Length);
writer.Write(pcmData);
}
}
void SaveFileImageAndShow(byte[] imageData, string filePath, RawImage rawImage)
{
File.WriteAllBytes(filePath, imageData);
Texture2D texture = new Texture2D(1, 1);
texture.LoadImage(imageData);
rawImage.texture = texture;
float aspectRatio = (float)texture.width / (float)texture.height;
rawImage.GetComponent<AspectRatioFitter>().aspectRatio = aspectRatio;
}
void SaveFileVideoAndShow(byte[] videoData, string filePath, VideoPlayer videoPlayer)
{
File.WriteAllBytes(filePath, videoData);
videoPlayer.source = VideoSource.Url;
videoPlayer.url = filePath;
videoPlayer.Play();
}
}