36cbe62fe1
status / cancel / list_providers were near-identical across GenerateAudio,
GenerateImage and GenerateModel (differing only by a kind label + poll
interval), and NormalizeOutputFolder was a verbatim triple copy.
- New AssetGenToolHelpers.{Status,Cancel,ListProviders} — the three tools now
delegate, passing their kind label / poll interval.
- NormalizeOutputFolder moved to AssetGenPaths (it already lived on
TryGetAssetsFolder).
- Behaviour preserved (image `remove_background` arm kept; provider-list
filtering unchanged). Net -120 lines of duplication.
Verified: EditMode 1167 tests / 0 failures + in-editor smoke (audio/image/model
list_providers, status/cancel error paths, image remove_background all intact).
Claude-Session: https://claude.ai/code/session_015KYy51gwBuhDuLZXXoqc98
88 lines
4.1 KiB
C#
88 lines
4.1 KiB
C#
using System;
|
|
using MCPForUnity.Editor.Helpers;
|
|
using MCPForUnity.Editor.Security;
|
|
using MCPForUnity.Editor.Services.AssetGen;
|
|
using MCPForUnity.Editor.Services.AssetGen.Providers;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace MCPForUnity.Editor.Tools.AssetGen
|
|
{
|
|
/// <summary>
|
|
/// Audio generation (SFX / music) via fal.ai. Triggered here (never from the GUI); the C# side
|
|
/// reads the fal key from the secure store and runs the job. Returns a job_id immediately; the
|
|
/// client polls the `status` action. When `model` is omitted it falls back to the model selected
|
|
/// in the Asset Generation tab, then the catalog default. Status / cancel / list_providers are
|
|
/// shared across the generate_* tools via <see cref="AssetGenToolHelpers"/>.
|
|
/// </summary>
|
|
[McpForUnityTool("generate_audio", AutoRegister = false, Group = "asset_gen", RequiresPolling = true, PollAction = "status", MaxPollSeconds = 600)]
|
|
public static class GenerateAudio
|
|
{
|
|
public static object HandleCommand(JObject @params)
|
|
{
|
|
if (@params == null) return new ErrorResponse("Parameters cannot be null.");
|
|
var p = new ToolParams(@params);
|
|
string action = (p.Get("action") ?? string.Empty).ToLowerInvariant();
|
|
try
|
|
{
|
|
switch (action)
|
|
{
|
|
case "generate": return Generate(p);
|
|
case "status": return AssetGenToolHelpers.Status(p, "Audio", 3.0);
|
|
case "cancel": return AssetGenToolHelpers.Cancel(p);
|
|
case "list_providers": return AssetGenToolHelpers.ListProviders("audio");
|
|
case "": return new ErrorResponse("'action' parameter is required.");
|
|
default:
|
|
return new ErrorResponse($"Unknown action: '{action}'. Supported: generate, status, cancel, list_providers.");
|
|
}
|
|
}
|
|
catch (NotSupportedException nse)
|
|
{
|
|
return new ErrorResponse(nse.Message);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return new ErrorResponse(SecretRedactor.Scrub(e.Message));
|
|
}
|
|
}
|
|
|
|
private static object Generate(ToolParams p)
|
|
{
|
|
string provider = (p.Get("provider", "fal") ?? "fal").ToLowerInvariant();
|
|
AssetGenProviders.Audio(provider); // throws NotSupportedException for unknown providers
|
|
|
|
if (!SecureKeyStore.Current.Has(provider))
|
|
return new ErrorResponse(AssetGenProviders.MissingKeyMessage(provider));
|
|
|
|
string prompt = p.Get("prompt");
|
|
if (string.IsNullOrWhiteSpace(prompt))
|
|
return new ErrorResponse("'prompt' is required for audio generation.");
|
|
|
|
// Empty -> GUI-selected model -> catalog default. A null model reaches the adapter's own
|
|
// default; a resolved id is passed through verbatim (the catalog default equals the
|
|
// adapter constant, so an omitted model is a no-op either way).
|
|
string model = AssetGenModelCatalog.ResolveModel("audio", provider, p.Get("model"));
|
|
|
|
var req = new AudioGenRequest
|
|
{
|
|
Provider = provider,
|
|
Model = model,
|
|
Prompt = prompt,
|
|
Duration = p.GetFloat("duration", 0f) ?? 0f,
|
|
Name = p.Get("name"),
|
|
OutputFolder = p.Get("outputFolder"),
|
|
};
|
|
if (!AssetGenPaths.NormalizeOutputFolder(req.OutputFolder, out req.OutputFolder, out string outputErr))
|
|
return new ErrorResponse(outputErr);
|
|
|
|
AssetGenJob job = AssetGenJobManager.StartAudioGeneration(req);
|
|
if (job.State == AssetGenJobState.Failed)
|
|
return new ErrorResponse(job.Error ?? "Failed to start generation.");
|
|
|
|
return new PendingResponse(
|
|
$"Audio generation started with '{provider}'. Poll the status action with this job_id.",
|
|
pollIntervalSeconds: 3.0,
|
|
data: new { job_id = job.JobId, provider, status = "pending" });
|
|
}
|
|
}
|
|
}
|