.csファイル
using System.Text;
using System.Text.Json;
using Amazon;
using Amazon.BedrockRuntime;
using Amazon.BedrockRuntime.Model;
namespace BedrockImageGUI;
public class Form1 : Form
{
TextBox txtPrompt = new()
{
Multiline = true,
ScrollBars = ScrollBars.Vertical,
Height = 80,
Text = "この画像について詳しく説明してください。v3",
Dock = DockStyle.Top
};
PictureBox pic = new()
{
Height = 240,
SizeMode = PictureBoxSizeMode.Zoom,
Dock = DockStyle.Top,
BorderStyle = BorderStyle.FixedSingle
};
Button btnImage = new() { Text = "画像を選ぶ", Dock = DockStyle.Top };
Button btnSend = new() { Text = "送信(Claude)", Dock = DockStyle.Top };
TextBox txtOutput = new()
{
Multiline = true,
ScrollBars = ScrollBars.Vertical,
ReadOnly = true,
Dock = DockStyle.Fill
};
string imagePath = "";
public Form1()
{
Text = "Claude × Claude Vision(最小GUI)";
Width = 900;
Height = 700;
Controls.Add(txtOutput);
Controls.Add(btnSend);
Controls.Add(btnImage);
Controls.Add(pic);
Controls.Add(txtPrompt);
btnImage.Click += (_, _) =>
{
using var ofd = new OpenFileDialog();
if (ofd.ShowDialog() == DialogResult.OK)
{
imagePath = ofd.FileName;
pic.Image = Image.FromFile(imagePath);
}
};
btnSend.Click += async (_, _) => await SendAsync();
}
async Task SendAsync()
{
if (string.IsNullOrEmpty(imagePath))
{
MessageBox.Show("先に画像を選択してください。");
return;
}
btnSend.Enabled = false;
var oldText = btnSend.Text;
btnSend.Text = "送信中…";
txtOutput.Text = "実行中…";
try
{
var base64Image = Convert.ToBase64String(File.ReadAllBytes(imagePath));
var mediaType = GetMediaType(imagePath);
// ★ 送信順は「テキスト → 画像」(元コードのまま)
var messages = new[]
{
new Dictionary<string, object>
{
["role"] = "user",
["content"] = new List<Dictionary<string, object>>
{
new() { ["type"] = "text", ["text"] = txtPrompt.Text },
new()
{
["type"] = "image",
["source"] = new Dictionary<string, string>
{
["type"] = "base64",
["media_type"] = mediaType,
["data"] = base64Image
}
}
}
}
};
var payload = new Dictionary<string, object>
{
["anthropic_version"] = "bedrock-2023-05-31",
["max_tokens"] = 1024,
["messages"] = messages
};
var request = new InvokeModelRequest
{
Body = new MemoryStream(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(payload))),
ContentType = "application/json",
Accept = "application/json",
ModelId = "anthropic.claude-3-sonnet-20240229-v1:0"
};
var client = new AmazonBedrockRuntimeClient(RegionEndpoint.USEast1);
var response = await client.InvokeModelAsync(request);
using var reader = new StreamReader(response.Body);
var json = await reader.ReadToEndAsync();
// ★ 改行ありで表示:content配列のtext要素をすべて結合し、\n→環境改行に
var root = JsonDocument.Parse(json).RootElement;
var content = root.GetProperty("content");
var sb = new StringBuilder();
foreach (var part in content.EnumerateArray())
{
if (part.TryGetProperty("type", out var t) && t.GetString() == "text")
{
var piece = part.GetProperty("text").GetString() ?? "";
sb.AppendLine(piece);
}
}
var text = sb.ToString();
if (!string.IsNullOrEmpty(text))
{
text = text.Replace("\n", Environment.NewLine);
}
txtOutput.Text = text;
}
catch (Exception ex)
{
txtOutput.Text = $"エラー: {ex.Message}";
}
finally
{
btnSend.Text = oldText;
btnSend.Enabled = true;
}
}
static string GetMediaType(string path)
{
var ext = Path.GetExtension(path).ToLowerInvariant();
return ext switch
{
".png" => "image/png",
".jpg" or ".jpeg" => "image/jpeg",
".webp" => "image/webp",
".bmp" => "image/bmp",
_ => "image/png"
};
}
}
program.cs
namespace BedrockImageGUI;
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AWSSDK.BedrockRuntime" Version="4.0.3.1" />
</ItemGroup>
</Project>