#include "pipeline.h" #include #include #include #include #include static PIJSON promptToJSON(const Prompt & p) { PIJSON j = PIJSON::newObject(); j["id"] = p.id; j["text"] = p.text; j["title"] = p.title; j["order"] = p.order; return j; } static Prompt promptFromJSON(const PIJSON & j) { Prompt p; p.id = j["id"].toString(); p.text = j["text"].toString(); p.title = j["title"].toString(); p.order = j["order"].toInt(); return p; } static PIJSON pipelineToJSON(const Pipeline & pl) { PIJSON j = PIJSON::newObject(); j["id"] = pl.id; j["name"] = pl.name; j["working_dir"] = pl.working_dir; j["created_at"] = pl.created_at; j["updated_at"] = pl.updated_at; PIJSON arr = PIJSON::newArray(); for (const auto & p: pl.prompts) { arr << promptToJSON(p); } j["prompts"] = arr; return j; } static Pipeline pipelineFromJSON(const PIJSON & j) { Pipeline pl; pl.id = j["id"].toString(); pl.name = j["name"].toString(); pl.working_dir = j["working_dir"].toString(); pl.created_at = j["created_at"].toString(); pl.updated_at = j["updated_at"].toString(); PIJSON promptsJ = j["prompts"]; if (promptsJ.isArray()) { const auto & promptsArr = promptsJ.array(); for (int i = 0; i < promptsArr.size(); ++i) { if (promptsArr[i].isObject()) { pl.prompts << promptFromJSON(promptsArr[i]); } } } return pl; } PIVector loadPipelines(const PIString & pipelines_dir) { PIVector result; PIDir dir(pipelines_dir); if (!dir.isExists()) return result; const auto entries = dir.entries(); for (const auto & entry: entries) { if (!entry.isFile() || entry.extension() != "json") continue; PIByteArray data = PIFile::readAll(entry.path); PIJSON j = PIJSON::fromJSON(PIString::fromUTF8(data)); if (j.isObject()) { result << pipelineFromJSON(j); } } // Sort by updated_at descending result.sort([](const Pipeline & a, const Pipeline & b) { return a.updated_at > b.updated_at; }); return result; } bool savePipeline(const PIString & pipelines_dir, Pipeline & pipeline) { pipeline.updated_at = nowISO(); PIJSON j = pipelineToJSON(pipeline); PIString path = pipelines_dir + pipeline.id + ".json"; return PIFile::writeAll(path, j.toJSON(PIJSON::Tree).toUTF8()); } bool deletePipeline(const PIString & pipelines_dir, const PIString & pipeline_id) { PIString path = pipelines_dir + pipeline_id + ".json"; return PIFile::remove(path); } Pipeline findPipeline(const PIString & pipelines_dir, const PIString & pipeline_id) { PIString path = pipelines_dir + pipeline_id + ".json"; if (!PIFile::isExists(path)) return Pipeline(); PIByteArray data = PIFile::readAll(path); PIJSON j = PIJSON::fromJSON(PIString::fromUTF8(data)); if (j.isObject()) { return pipelineFromJSON(j); } return Pipeline(); } void appendLog(const PIString & logs_dir, const PIString & run_id, const PIString & line) { PIString path = logs_dir + run_id + ".log"; PIFile f(path, PIIODevice::ReadWrite); if (f.isOpened()) { f.seekToEnd(); PIString ts = nowISO(); f.write((ts + " " + line + "\n").toUTF8()); f.close(); } } PIString readLog(const PIString & logs_dir, const PIString & run_id) { PIString path = logs_dir + run_id + ".log"; if (!PIFile::isExists(path)) return PIString(); PIByteArray data = PIFile::readAll(path); return PIString::fromUTF8(data); } PIString generateUUID() { PIByteArray bytes = PICrypt::generateRandomBuff(16); PIString hex = bytes.toHex(); // Format as UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx return hex.left(8) + "-" + hex.mid(8, 4) + "-" + hex.mid(12, 4) + "-" + hex.mid(16, 4) + "-" + hex.mid(20, 12); } static PIString pad2(int v) { return v < 10 ? "0" + PIString::fromNumber(v) : PIString::fromNumber(v); } PIString nowISO() { PIDateTime dt = PIDateTime::current(); return PIString::fromNumber(dt.year) + "-" + pad2(dt.month) + "-" + pad2(dt.day) + "T" + pad2(dt.hours) + ":" + pad2(dt.minutes) + ":" + pad2(dt.seconds) + "Z"; }