File Attachments
Send files and images along with your messages.
Overview
AI Dev Kit supports:
Images (PNG, JPG, WebP, GIF)
Documents (for File Search tool)
Code files (for Code Interpreter)
Audio files (for transcription)
Image Attachments
Send Image with Message
// Load image
Texture2D image = LoadImage();
// Send with text
Response response = await agent.SendAsync(
message: "What's in this image?",
image: image
);
Debug.Log(response.Text);Image Only
// Send image without text (uses default prompt)
Response response = await agent.SendAsync(
message: "",
image: image
);Multiple Images (Not Directly Supported)
// Send multiple images by adding to message manually
var message = new Message
{
Role = Role.User,
Parts = new List<ContentPart>
{
new ContentPart { Type = "text", Text = "Compare these images:" },
new ContentPart
{
Type = "image_url",
ImageUrl = new ImageUrl
{
Url = ConvertToBase64(image1),
Detail = "high"
}
},
new ContentPart
{
Type = "image_url",
ImageUrl = new ImageUrl
{
Url = ConvertToBase64(image2),
Detail = "high"
}
}
}
};
agent.Conversation.Messages.Add(message);
await agent.SendAsync("");Image Formats
Convert Texture2D to Base64
public string ConvertToBase64(Texture2D texture)
{
byte[] imageBytes = texture.EncodeToPNG();
string base64 = Convert.ToBase64String(imageBytes);
return $"data:image/png;base64,{base64}";
}Load from File
public Texture2D LoadImageFromFile(string path)
{
byte[] bytes = File.ReadAllBytes(path);
Texture2D texture = new Texture2D(2, 2);
texture.LoadImage(bytes);
return texture;
}
// Usage
Texture2D image = LoadImageFromFile("screenshot.png");
await agent.SendAsync("Analyze this", image);From Screenshot
public async UniTask SendScreenshot(string question)
{
// Capture screenshot
Texture2D screenshot = ScreenCapture.CaptureScreenshotAsTexture();
// Send to agent
Response response = await agent.SendAsync(question, screenshot);
Debug.Log(response.Text);
// Cleanup
Destroy(screenshot);
}From Camera
public async UniTask AnalyzeCameraView(Camera camera)
{
// Render camera to texture
RenderTexture rt = new RenderTexture(512, 512, 24);
camera.targetTexture = rt;
camera.Render();
// Convert to Texture2D
RenderTexture.active = rt;
Texture2D screenshot = new Texture2D(512, 512, TextureFormat.RGB24, false);
screenshot.ReadPixels(new Rect(0, 0, 512, 512), 0, 0);
screenshot.Apply();
// Cleanup
camera.targetTexture = null;
RenderTexture.active = null;
Destroy(rt);
// Send to agent
await agent.SendAsync("What do you see?", screenshot);
Destroy(screenshot);
}Image Detail Levels
High vs Low Detail
// High detail (more tokens, better accuracy)
var highDetailPart = new ContentPart
{
Type = "image_url",
ImageUrl = new ImageUrl
{
Url = imageBase64,
Detail = "high" // ~765 tokens per image
}
};
// Low detail (fewer tokens, faster)
var lowDetailPart = new ContentPart
{
Type = "image_url",
ImageUrl = new ImageUrl
{
Url = imageBase64,
Detail = "low" // ~85 tokens per image
}
};Document Attachments
Upload for File Search
// Upload document to OpenAI
public async UniTask<string> UploadDocument(string filePath)
{
byte[] fileBytes = File.ReadAllBytes(filePath);
string fileName = Path.GetFileName(filePath);
// Upload via OpenAI API
var fileInfo = await openAIClient.Files.UploadFileAsync(
file: fileBytes,
fileName: fileName,
purpose: "assistants"
);
return fileInfo.Id;
}
// Add to agent tools
agent.Settings.ToolDefinitions.Add(new FileSearchToolDefinition
{
FileIds = new[] { fileId }
});Use with File Search Tool
// Enable File Search tool
agent.Settings.EnableFileSearch = true;
agent.Settings.FileSearchFileIds = new[] { fileId };
// Ask questions about the document
await agent.SendAsync("What does the document say about pricing?");Code File Attachments
Send Code for Analysis
public async UniTask AnalyzeCodeFile(string filePath)
{
string code = File.ReadAllText(filePath);
string fileName = Path.GetFileName(filePath);
string message = $@"
Analyze this {Path.GetExtension(filePath)} file:
File: {fileName}
```{Path.GetExtension(filePath).TrimStart('.')}
{code}What improvements would you suggest? ";
Response response = await agent.SendAsync(message);
Debug.Log(response.Text);}
### Use Code Interpreter
```csharp
// Enable Code Interpreter tool
agent.Settings.EnableCodeInterpreter = true;
// Upload code file
string fileId = await UploadDocument("script.py");
// Ask agent to execute it
await agent.SendAsync("Run this Python script and show me the output");Audio File Attachments
Send Audio for Transcription
public async UniTask<string> TranscribeAudioFile(string audioPath)
{
// Load audio clip
AudioClip clip = LoadAudioClip(audioPath);
// Transcribe
string transcription = await agent.TranscribeAsync(clip);
Debug.Log($"Transcription: {transcription}");
return transcription;
}Send Audio as Message
AudioClip clip = LoadAudioClip("recording.wav");
// Send audio (will be transcribed automatically if enabled)
Response response = await agent.SendAsync(clip);
Debug.Log(response.Text);File Size Limits
Check File Size
public bool IsFileSizeValid(string filePath, long maxSizeBytes = 20_000_000)
{
FileInfo fileInfo = new FileInfo(filePath);
if (fileInfo.Length > maxSizeBytes)
{
Debug.LogError($"File too large: {fileInfo.Length} bytes (max: {maxSizeBytes})");
return false;
}
return true;
}Compress Images
public Texture2D CompressImage(Texture2D original, int maxDimension = 1024)
{
if (original.width <= maxDimension && original.height <= maxDimension)
{
return original;
}
// Calculate new size maintaining aspect ratio
float scale = Mathf.Min(
(float)maxDimension / original.width,
(float)maxDimension / original.height
);
int newWidth = Mathf.RoundToInt(original.width * scale);
int newHeight = Mathf.RoundToInt(original.height * scale);
// Resize
RenderTexture rt = RenderTexture.GetTemporary(newWidth, newHeight);
Graphics.Blit(original, rt);
RenderTexture.active = rt;
Texture2D compressed = new Texture2D(newWidth, newHeight);
compressed.ReadPixels(new Rect(0, 0, newWidth, newHeight), 0, 0);
compressed.Apply();
RenderTexture.active = null;
RenderTexture.ReleaseTemporary(rt);
return compressed;
}Error Handling
Invalid File Types
public async UniTask<Response> SendImageSafe(string imagePath)
{
string extension = Path.GetExtension(imagePath).ToLower();
string[] validExtensions = { ".png", ".jpg", ".jpeg", ".webp", ".gif" };
if (!validExtensions.Contains(extension))
{
throw new ArgumentException($"Invalid image format: {extension}");
}
Texture2D image = LoadImageFromFile(imagePath);
return await agent.SendAsync("Analyze this image", image);
}File Not Found
try
{
Texture2D image = LoadImageFromFile(path);
await agent.SendAsync("What's this?", image);
}
catch (FileNotFoundException)
{
Debug.LogError($"Image not found: {path}");
}
catch (Exception ex)
{
Debug.LogError($"Failed to load image: {ex.Message}");
}Complete Example
using UnityEngine;
using Glitch9.AIDevKit.Agents;
using Cysharp.Threading.Tasks;
using System;
using System.IO;
public class FileAttachmentManager : MonoBehaviour
{
[SerializeField] private AgentBehaviour agent;
public async void AnalyzeScreenshot()
{
// Capture
Texture2D screenshot = ScreenCapture.CaptureScreenshotAsTexture();
// Compress if needed
Texture2D compressed = CompressImage(screenshot, 1024);
try
{
// Send to agent
Response response = await agent.SendAsync(
"Describe what you see in this screenshot. What is the user likely doing?",
compressed
);
Debug.Log($"Analysis: {response.Text}");
}
finally
{
// Cleanup
Destroy(screenshot);
if (compressed != screenshot)
{
Destroy(compressed);
}
}
}
public async void AnalyzeImage(string imagePath)
{
if (!File.Exists(imagePath))
{
Debug.LogError($"File not found: {imagePath}");
return;
}
// Validate
if (!IsImageFile(imagePath))
{
Debug.LogError("Not a valid image file");
return;
}
// Load
Texture2D image = LoadImageFromFile(imagePath);
try
{
// Send
Response response = await agent.SendAsync(
"What's in this image?",
image
);
Debug.Log(response.Text);
}
finally
{
Destroy(image);
}
}
bool IsImageFile(string path)
{
string ext = Path.GetExtension(path).ToLower();
return ext == ".png" || ext == ".jpg" || ext == ".jpeg" ||
ext == ".webp" || ext == ".gif";
}
Texture2D LoadImageFromFile(string path)
{
byte[] bytes = File.ReadAllBytes(path);
Texture2D texture = new Texture2D(2, 2);
texture.LoadImage(bytes);
return texture;
}
Texture2D CompressImage(Texture2D original, int maxDimension)
{
if (original.width <= maxDimension && original.height <= maxDimension)
{
return original;
}
float scale = Mathf.Min(
(float)maxDimension / original.width,
(float)maxDimension / original.height
);
int newWidth = Mathf.RoundToInt(original.width * scale);
int newHeight = Mathf.RoundToInt(original.height * scale);
RenderTexture rt = RenderTexture.GetTemporary(newWidth, newHeight);
Graphics.Blit(original, rt);
RenderTexture.active = rt;
Texture2D compressed = new Texture2D(newWidth, newHeight);
compressed.ReadPixels(new Rect(0, 0, newWidth, newHeight), 0, 0);
compressed.Apply();
RenderTexture.active = null;
RenderTexture.ReleaseTemporary(rt);
return compressed;
}
}Next Steps
Last updated