Skip to content

Commit 6f8cfa1

Browse files
Merge pull request #119 from datalogics-dliang/summary-samples
PDFCLOUD-5245 Add samples for /summarized-pdf-text
2 parents a651cc8 + 1dc020d commit 6f8cfa1

25 files changed

Lines changed: 1327 additions & 0 deletions

File tree

CPlusPlus/Endpoint Examples/JSON Payload/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,8 @@ if (cpr_FOUND AND nlohmann_json_FOUND)
1111
add_executable(rasterized_pdf_json rasterized_pdf.cpp)
1212
target_link_libraries(rasterized_pdf_json PRIVATE cpr::cpr nlohmann_json::nlohmann_json)
1313
target_compile_features(rasterized_pdf_json PRIVATE cxx_std_20)
14+
15+
add_executable(summarized_pdf_text_json summarized_pdf_text.cpp)
16+
target_link_libraries(summarized_pdf_text_json PRIVATE cpr::cpr nlohmann_json::nlohmann_json)
17+
target_compile_features(summarized_pdf_text_json PRIVATE cxx_std_20)
1418
endif()
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* What this sample does:
3+
* - Uploads a PDF via /upload, then calls /summarized-pdf-text with a JSON payload
4+
* referencing the uploaded resource id (two-step JSON flow).
5+
*
6+
* Setup (environment):
7+
* - Set PDFREST_API_KEY=your_api_key_here
8+
* - Optional: set PDFREST_URL to override the API region. For EU/GDPR, use:
9+
* PDFREST_URL=https://eu-api.pdfrest.com
10+
* More info: https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
11+
*
12+
* Usage:
13+
* ./summarized_pdf_text_json /path/to/input.pdf
14+
*
15+
* Output:
16+
* - Prints JSON responses to stdout. Non-2xx responses print a concise
17+
* error to stderr and exit non-zero.
18+
*/
19+
20+
#include <cpr/cpr.h>
21+
#include <nlohmann/json.hpp>
22+
23+
#include <cstdlib>
24+
#include <filesystem>
25+
#include <fstream>
26+
#include <iostream>
27+
#include <optional>
28+
#include <string>
29+
30+
namespace fs = std::filesystem;
31+
using json = nlohmann::json;
32+
33+
static std::string rtrim_slashes(std::string s) {
34+
while (!s.empty() && (s.back() == '/' || s.back() == '\\')) {
35+
s.pop_back();
36+
}
37+
return s;
38+
}
39+
40+
static void load_dotenv_if_present(const fs::path &path) {
41+
std::ifstream f(path);
42+
if (!f.is_open()) return;
43+
std::string line;
44+
while (std::getline(f, line)) {
45+
if (line.empty() || line[0] == '#') continue;
46+
auto pos = line.find('=');
47+
if (pos == std::string::npos) continue;
48+
std::string key = line.substr(0, pos);
49+
std::string val = line.substr(pos + 1);
50+
auto trim = [](std::string &s) {
51+
size_t start = s.find_first_not_of(" \t\r\n");
52+
size_t end = s.find_last_not_of(" \t\r\n");
53+
if (start == std::string::npos) { s.clear(); return; }
54+
s = s.substr(start, end - start + 1);
55+
};
56+
trim(key);
57+
trim(val);
58+
if (key.empty()) continue;
59+
#ifdef _WIN32
60+
_putenv_s(key.c_str(), val.c_str());
61+
#else
62+
if (std::getenv(key.c_str()) == nullptr) setenv(key.c_str(), val.c_str(), 0);
63+
#endif
64+
}
65+
}
66+
67+
static void load_env() {
68+
const fs::path here = fs::current_path();
69+
load_dotenv_if_present(here / ".env");
70+
if (fs::exists(here.parent_path())) {
71+
load_dotenv_if_present(here.parent_path() / ".env");
72+
}
73+
}
74+
75+
static std::optional<std::string> read_file_to_string(const fs::path &p) {
76+
std::ifstream in(p, std::ios::binary);
77+
if (!in) return std::nullopt;
78+
std::string data((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
79+
return data;
80+
}
81+
82+
int main(int argc, char *argv[]) {
83+
load_env();
84+
if (argc < 2) {
85+
std::cerr << "Usage: summarized_pdf_text_json <input.pdf>\n";
86+
return 1;
87+
}
88+
fs::path input_path(argv[1]);
89+
if (!fs::exists(input_path)) {
90+
std::cerr << "File not found: " << input_path << "\n";
91+
return 1;
92+
}
93+
94+
const char *api_key_c = std::getenv("PDFREST_API_KEY");
95+
if (api_key_c == nullptr || std::string(api_key_c).empty()) {
96+
std::cerr << "Missing required environment variable: PDFREST_API_KEY\n";
97+
return 1;
98+
}
99+
std::string api_key = api_key_c;
100+
101+
const char *base_url_c = std::getenv("PDFREST_URL");
102+
std::string base_url = base_url_c && std::string(base_url_c).size() ? base_url_c : std::string("https://api.pdfrest.com");
103+
base_url = rtrim_slashes(base_url);
104+
105+
auto maybe_data = read_file_to_string(input_path);
106+
if (!maybe_data) {
107+
std::cerr << "Failed to read input file: " << input_path << "\n";
108+
return 1;
109+
}
110+
std::string body = std::move(*maybe_data);
111+
112+
cpr::Header headers{{"Api-Key", api_key}, {"Accept", "application/json"}, {"Content-Type", "application/octet-stream"}, {"Content-Filename", input_path.filename().string()}};
113+
auto res = cpr::Post(cpr::Url{base_url + "/upload"}, headers, cpr::Body{body});
114+
if (res.error || res.status_code < 200 || res.status_code >= 300) {
115+
std::cerr << "Upload failed (status " << res.status_code << "): " << res.error.message << "\n" << res.text << "\n";
116+
return 1;
117+
}
118+
std::cout << res.text << "\n";
119+
120+
std::string uploaded_id;
121+
try {
122+
auto j = json::parse(res.text);
123+
uploaded_id = j.at("files").at(0).at("id").get<std::string>();
124+
} catch (const std::exception &e) {
125+
std::cerr << "Failed to parse upload id: " << e.what() << "\n";
126+
return 1;
127+
}
128+
129+
json payload = { {"id", uploaded_id}, {"target_word_count", 100} };
130+
131+
cpr::Header sum_headers{{"Api-Key", api_key}, {"Accept", "application/json"}, {"Content-Type", "application/json"}};
132+
auto sum_res = cpr::Post(cpr::Url{base_url + "/summarized-pdf-text"}, sum_headers, cpr::Body{payload.dump()});
133+
if (sum_res.error || sum_res.status_code < 200 || sum_res.status_code >= 300) {
134+
std::cerr << "Summarize failed (status " << sum_res.status_code << "): " << sum_res.error.message << "\n" << sum_res.text << "\n";
135+
return 1;
136+
}
137+
std::cout << sum_res.text << "\n";
138+
return 0;
139+
}

CPlusPlus/Endpoint Examples/Multipart Payload/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,8 @@ if (cpr_FOUND)
1010
add_executable(rasterized_pdf_multipart rasterized_pdf.cpp)
1111
target_link_libraries(rasterized_pdf_multipart PRIVATE cpr::cpr)
1212
target_compile_features(rasterized_pdf_multipart PRIVATE cxx_std_20)
13+
14+
add_executable(summarized_pdf_text_multipart summarized_pdf_text.cpp)
15+
target_link_libraries(summarized_pdf_text_multipart PRIVATE cpr::cpr)
16+
target_compile_features(summarized_pdf_text_multipart PRIVATE cxx_std_20)
1317
endif()
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* What this sample does:
3+
* - Summarizes PDF content via multipart/form-data (file + options).
4+
*
5+
* Setup (environment):
6+
* - Copy .env.example to .env
7+
* - Set PDFREST_API_KEY=your_api_key_here
8+
* - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use:
9+
* PDFREST_URL=https://eu-api.pdfrest.com
10+
* For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
11+
*
12+
* Usage:
13+
* ./summarized_pdf_text_multipart /path/to/input.pdf
14+
*
15+
* Output:
16+
* - Prints the JSON response to stdout; non-2xx exits with concise error.
17+
*/
18+
19+
#include <cpr/cpr.h>
20+
#include <filesystem>
21+
#include <iostream>
22+
#include <fstream>
23+
#include <cstdlib>
24+
25+
namespace fs = std::filesystem;
26+
27+
static std::string rtrim_slashes(std::string s) {
28+
while (!s.empty() && (s.back() == '/' || s.back() == '\\')) s.pop_back();
29+
return s;
30+
}
31+
32+
static void load_dotenv_if_present(const fs::path &path) {
33+
std::ifstream f(path);
34+
if (!f.is_open()) return;
35+
std::string line;
36+
while (std::getline(f, line)) {
37+
if (line.empty() || line[0] == '#') continue;
38+
auto p = line.find('=');
39+
if (p == std::string::npos) continue;
40+
std::string k = line.substr(0, p);
41+
std::string v = line.substr(p + 1);
42+
auto trim = [](std::string &s) { size_t b = s.find_first_not_of(" \t\r\n"), e = s.find_last_not_of(" \t\r\n"); if (b == std::string::npos) { s.clear(); return; } s = s.substr(b, e - b + 1); };
43+
trim(k); trim(v);
44+
#ifdef _WIN32
45+
_putenv_s(k.c_str(), v.c_str());
46+
#else
47+
if (!std::getenv(k.c_str())) setenv(k.c_str(), v.c_str(), 0);
48+
#endif
49+
}
50+
}
51+
52+
static void load_env() {
53+
auto here = fs::current_path();
54+
load_dotenv_if_present(here / ".env");
55+
if (fs::exists(here.parent_path())) load_dotenv_if_present(here.parent_path() / ".env");
56+
}
57+
58+
int main(int argc, char **argv) {
59+
load_env();
60+
if (argc < 2) { std::cerr << "Usage: summarized_pdf_text_multipart <input.pdf>\n"; return 1; }
61+
fs::path input = argv[1];
62+
if (!fs::exists(input)) { std::cerr << "File not found: " << input << "\n"; return 1; }
63+
const char *key = getenv("PDFREST_API_KEY");
64+
if (!key || !*key) { std::cerr << "Missing PDFREST_API_KEY\n"; return 1; }
65+
std::string base = getenv("PDFREST_URL") ? getenv("PDFREST_URL") : "https://api.pdfrest.com";
66+
base = rtrim_slashes(base);
67+
68+
cpr::Header hdr{{"Api-Key", key}, {"Accept", "application/json"}};
69+
cpr::Multipart mp{
70+
{"file", cpr::File{input.string()}},
71+
{"target_word_count", "100"}
72+
};
73+
auto res = cpr::Post(cpr::Url{base + "/summarized-pdf-text"}, hdr, mp);
74+
if (res.error || res.status_code < 200 || res.status_code >= 300) {
75+
std::cerr << "Request failed (" << res.status_code << ")\n" << res.error.message << "\n" << res.text << "\n";
76+
return 1;
77+
}
78+
std::cout << res.text << "\n";
79+
return 0;
80+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* What this sample does:
3+
* - Implements a command callable from Program.cs that uploads a file and
4+
* then summarizes the content in the file via the JSON two-step flow.
5+
* - Routes `dotnet run -- summarized-pdf-text <inputFile>` to this module.
6+
*
7+
* Setup (environment):
8+
* - Copy .env.example to .env
9+
* - Set PDFREST_API_KEY=your_api_key_here
10+
* - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use:
11+
* PDFREST_URL=https://eu-api.pdfrest.com
12+
* For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
13+
*/
14+
15+
using Newtonsoft.Json.Linq;
16+
using System.Text;
17+
18+
namespace Samples.EndpointExamples.JsonPayload
19+
{
20+
public static class SummarizedPdfText
21+
{
22+
public static async Task Execute(string[] args)
23+
{
24+
if (args == null || args.Length < 1)
25+
{
26+
Console.Error.WriteLine("summarized-pdf-text requires <inputFile>");
27+
Environment.Exit(1);
28+
return;
29+
}
30+
31+
var inputPath = args[0];
32+
if (!File.Exists(inputPath))
33+
{
34+
Console.Error.WriteLine($"File not found: {inputPath}");
35+
Environment.Exit(1);
36+
return;
37+
}
38+
39+
var apiKey = Environment.GetEnvironmentVariable("PDFREST_API_KEY");
40+
if (string.IsNullOrWhiteSpace(apiKey))
41+
{
42+
Console.Error.WriteLine("Missing required environment variable: PDFREST_API_KEY");
43+
Environment.Exit(1);
44+
return;
45+
}
46+
47+
var baseUrl = Environment.GetEnvironmentVariable("PDFREST_URL") ?? "https://api.pdfrest.com";
48+
49+
using (var httpClient = new HttpClient { BaseAddress = new Uri(baseUrl) })
50+
{
51+
using (var uploadRequest = new HttpRequestMessage(HttpMethod.Post, "upload"))
52+
{
53+
uploadRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey);
54+
uploadRequest.Headers.Accept.Add(new("application/json"));
55+
56+
var uploadByteArray = File.ReadAllBytes(inputPath);
57+
var uploadByteAryContent = new ByteArrayContent(uploadByteArray);
58+
uploadByteAryContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
59+
uploadByteAryContent.Headers.TryAddWithoutValidation("Content-Filename", Path.GetFileName(inputPath));
60+
61+
uploadRequest.Content = uploadByteAryContent;
62+
var uploadResponse = await httpClient.SendAsync(uploadRequest);
63+
64+
var uploadResult = await uploadResponse.Content.ReadAsStringAsync();
65+
66+
Console.WriteLine("Upload response received.");
67+
Console.WriteLine(uploadResult);
68+
69+
JObject uploadResultJson = JObject.Parse(uploadResult);
70+
var uploadedID = uploadResultJson["files"][0]["id"];
71+
using (var summaryRequest = new HttpRequestMessage(HttpMethod.Post, "summarized-pdf-text"))
72+
{
73+
summaryRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey);
74+
summaryRequest.Headers.Accept.Add(new("application/json"));
75+
summaryRequest.Headers.TryAddWithoutValidation("Content-Type", "application/json");
76+
77+
JObject parameterJson = new JObject
78+
{
79+
["id"] = uploadedID,
80+
["target_word_count"] = 100
81+
};
82+
83+
summaryRequest.Content = new StringContent(parameterJson.ToString(), Encoding.UTF8, "application/json");
84+
var summaryResponse = await httpClient.SendAsync(summaryRequest);
85+
86+
var summaryResult = await summaryResponse.Content.ReadAsStringAsync();
87+
88+
Console.WriteLine("Processing response received.");
89+
Console.WriteLine(summaryResult);
90+
}
91+
}
92+
}
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)