media:cpp --transform 1/3

This commit is contained in:
lovebird 2026-04-15 20:51:35 +02:00
parent 6bd416146b
commit 07dbf000f3
6 changed files with 52 additions and 3 deletions

View File

@ -145,6 +145,7 @@ add_executable(pm-image
src/core/glob_paths.cpp
src/core/output_path.cpp
src/core/resize.cpp
src/core/transform.cpp
src/core/url_fetch.cpp
src/http/serve.cpp
src/ipc/ipc_serve.cpp

Binary file not shown.

Binary file not shown.

View File

@ -10,14 +10,14 @@ namespace fs = std::filesystem;
namespace media {
namespace {
std::once_flag g_curl_init;
static std::once_flag g_curl_init;
void ensure_curl_global() {
std::call_once(g_curl_init, []() { curl_global_init(CURL_GLOBAL_DEFAULT); });
}
namespace {
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
auto *os = static_cast<std::ostream *>(userdata);
const size_t n = size * nmemb;

View File

@ -5,6 +5,9 @@
namespace media {
/// Call curl_global_init once (thread-safe via std::once_flag).
void ensure_curl_global();
bool is_http_url(const std::string &s);
/** Derive filename (last path segment) for single-file output when input is a URL. */

View File

@ -27,6 +27,7 @@ std::string join_src_semicolons(const std::vector<std::string> &v) {
#include "core/output_path.hpp"
#include "core/resize.hpp"
#include "core/transform.hpp"
#include "http/serve.hpp"
#include "ipc/ipc_serve.hpp"
#if defined(_WIN32)
@ -145,6 +146,23 @@ int main(int argc, char **argv) {
"Windows: new Win32++ ribbon UI with drag-drop queue and settings panel");
#endif
// ── transform (AI image editing) ──────────────────────────────────
std::string tf_input;
std::string tf_output;
std::string tf_prompt;
std::string tf_provider = "google";
std::string tf_model = "gemini-2.0-flash-exp";
std::string tf_api_key;
auto *transform_cmd = app.add_subcommand("transform", "AI image editing (Gemini / Google)");
transform_cmd->add_option("input", tf_input, "Input image path")->required(true);
transform_cmd->add_option("output", tf_output, "Output path (omit = auto from input + prompt)");
transform_cmd->add_option("-p,--prompt", tf_prompt, "Editing prompt")->required(true);
transform_cmd->add_option("--provider", tf_provider, "AI provider (google)")->default_val("google");
transform_cmd->add_option("--model", tf_model, "Model name")->default_val("gemini-2.0-flash-exp");
transform_cmd->add_option("--api-key", tf_api_key, "API key (or set IMAGE_TRANSFORM_GOOGLE_API_KEY env)");
// ── serve ───────────────────────────────────────────────────────────
std::string host = "127.0.0.1";
int port = 8080;
bool serve_no_cache = false;
@ -383,6 +401,33 @@ int main(int argc, char **argv) {
return 0;
}
if (transform_cmd->parsed()) {
media::TransformOptions topts;
topts.provider = tf_provider;
topts.model = tf_model;
topts.prompt = tf_prompt;
topts.api_key = tf_api_key;
if (topts.api_key.empty()) {
const char* env_key = std::getenv("IMAGE_TRANSFORM_GOOGLE_API_KEY");
if (env_key && env_key[0] != '\0') topts.api_key = env_key;
}
auto progress = [](const std::string& msg) {
std::cerr << msg << "\n";
};
auto result = media::transform_image(tf_input, tf_output, topts, progress);
if (!result.ok) {
std::cerr << "transform error: " << result.error << "\n";
return 1;
}
std::cout << result.output_path << "\n";
if (!result.ai_text.empty())
std::cerr << "AI: " << result.ai_text << "\n";
return 0;
}
if (serve_cmd->parsed()) {
media::CacheServerDefaults cd;
cd.enabled = !serve_no_cache;