UNPKG

neuwo-api

Version:

TypeScript/JavaScript SDK client for the Neuwo content classification API

311 lines 12.7 kB
"use strict"; /** * REST API client for Neuwo API. * * This module provides a client for analysis where content is provided directly as text. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.NeuwoRestClient = void 0; const errors_js_1 = require("./errors.js"); const logger_js_1 = require("./logger.js"); const models_js_1 = require("./models.js"); const utils_js_1 = require("./utils.js"); /** * Client for Neuwo REST API endpoints. * * REST endpoints operate over standard HTTP methods and use a REST API token passed as a query parameter. * REST endpoints are designed for server-side integration where content is provided directly as text. * The REST API serves publishers who want to enrich the data before publishing by analysing content. */ class NeuwoRestClient { /** * Initialise the REST API client. * * @param config - Client configuration * @param config.token - REST API authentication token * @param config.baseUrl - Base URL for the API server * @param config.timeout - Request timeout in seconds (default: 60) */ constructor(config) { if (!config.token || typeof config.token !== "string") { throw new errors_js_1.ValueError("Token must be a non-empty string"); } if (!config.baseUrl || typeof config.baseUrl !== "string") { throw new errors_js_1.ValueError("Base URL must be a non-empty string"); } const token = config.token.trim(); const baseUrl = config.baseUrl.trim().replace(/\/$/, ""); const timeout = config.timeout || NeuwoRestClient.DEFAULT_TIMEOUT; this.requestHandler = new utils_js_1.RequestHandler(token, baseUrl, timeout); logger_js_1.logger.info(`Initialised NeuwoRestClient with base URL: ${baseUrl}`); } /** * Retrieve AI-generated tags (raw response). * * Returns the raw HTTP response without parsing. Useful for custom processing or debugging. * * @returns Raw HTTP Response object * @throws {ValueError} If content is invalid * @throws {ValidationError} If parameters are invalid * @throws {AuthenticationError} If token is invalid * @throws {ForbiddenError} If token lacks permissions * @throws {NeuwoAPIError} For other API errors */ async getAiTopicsRaw(params) { params.format || (params.format = "json"); const content = (0, utils_js_1.sanitiseContent)(params.content); const data = { content, format: params.format, tag_limit: params.tagLimit !== undefined ? params.tagLimit : 15, tag_min_score: params.tagMinScore !== undefined ? params.tagMinScore : 0.1, marketing_min_score: params.marketingMinScore !== undefined ? params.marketingMinScore : 0.3, include_in_sim: params.includeInSim !== undefined ? params.includeInSim : true, }; if (params.documentId !== undefined) { data.documentid = params.documentId; } if (params.lang !== undefined) { data.lang = params.lang; } if (params.publicationId !== undefined) { data.publicationid = params.publicationId; } if (params.headline !== undefined) { data.headline = params.headline; } if (params.marketingLimit !== undefined) { data.marketing_limit = params.marketingLimit; } if (params.articleUrl !== undefined) { data.articleURL = params.articleUrl; } logger_js_1.logger.info(`Getting AI topics for content (length: ${content.length})`); return this.requestHandler.request({ method: "POST", endpoint: "/GetAiTopics", data, }); } /** * Retrieve AI-generated tags and classifications for text content. * * Sends text content to Neuwo's REST API to obtain AI-generated tag classifications * including subject tags, brand safety, marketing categories (IAB taxonomies), and * smart tags. Optionally saves the article in the database if documentId is provided. * * @returns GetAiTopicsResponse object containing tags, brand safety, marketing categories, and smart tags * @throws {ValueError} If content is invalid * @throws {ValidationError} If parameters are invalid * @throws {AuthenticationError} If token is invalid * @throws {ForbiddenError} If token lacks permissions * @throws {NeuwoAPIError} For other API errors */ async getAiTopics(params) { const response = await this.getAiTopicsRaw({ ...params, format: "json", }); const data = await (0, utils_js_1.parseJsonResponse)(response); const result = models_js_1.GetAiTopicsResponse.fromApiResponse(data); logger_js_1.logger.info(`Retrieved ${result.tags.length} tags and ${result.smartTags.length} smart tags`); return result; } /** * Find similar articles (raw response). * * Returns the raw HTTP response without parsing. * * @returns Raw HTTP Response object * @throws {ValidationError} If parameters are invalid * @throws {AuthenticationError} If token is invalid * @throws {ForbiddenError} If token lacks permissions * @throws {NeuwoAPIError} For other API errors */ async getSimilarRaw(params) { params.format || (params.format = "json"); const queryParams = { documentid: params.documentId, format: params.format, }; if (params.maxRows !== undefined) { queryParams.max_rows = params.maxRows; } if (params.pastDays !== undefined) { queryParams.past_days = params.pastDays; } if (params.publicationIds !== undefined) { queryParams.publicationid = params.publicationIds; } logger_js_1.logger.info(`Getting similar articles for document: ${params.documentId}`); return this.requestHandler.request({ method: "GET", endpoint: "/GetSimilar", params: queryParams, }); } /** * Find articles similar to the specified document. * * Returns a list of similar articles with metadata including articleID, headline, * articleURL, imageURL, similarity score, publication date, and publication ID. * * @returns Array of SimilarArticle objects with article metadata and similarity scores * @throws {ValidationError} If parameters are invalid * @throws {AuthenticationError} If token is invalid * @throws {ForbiddenError} If token lacks permissions * @throws {NeuwoAPIError} For other API errors */ async getSimilar(params) { const response = await this.getSimilarRaw({ ...params, format: "json", }); const data = await (0, utils_js_1.parseJsonResponse)(response); if (!Array.isArray(data)) { logger_js_1.logger.warning(`Expected array response, got: ${typeof data}`); return []; } const similarArticles = data.map((item) => models_js_1.SimilarArticle.fromApiResponse(item)); logger_js_1.logger.info(`Found ${similarArticles.length} similar articles`); return similarArticles; } /** * Update article fields (raw response). * * Returns the raw HTTP response without parsing. * * @returns Raw HTTP Response object * @throws {ValidationError} If parameters are invalid * @throws {AuthenticationError} If token is invalid * @throws {ForbiddenError} If token lacks permissions * @throws {NeuwoAPIError} For other API errors */ async updateArticleRaw(params) { params.format || (params.format = "json"); const data = { format: params.format, }; if (params.published !== undefined) { data.published = (0, utils_js_1.formatDate)(params.published); } if (params.headline !== undefined) { data.headline = params.headline; } if (params.writer !== undefined) { data.writer = params.writer; } if (params.category !== undefined) { data.category = params.category; } if (params.content !== undefined) { data.content = params.content; } if (params.summary !== undefined) { data.summary = params.summary; } if (params.publicationId !== undefined) { data.publicationid = params.publicationId; } if (params.articleUrl !== undefined) { data.articleURL = params.articleUrl; } if (params.imageUrl !== undefined) { data.imageURL = params.imageUrl; } if (params.includeInSim !== undefined) { data.include_in_sim = params.includeInSim; } logger_js_1.logger.info(`Updating article: ${params.documentId}`); return this.requestHandler.request({ method: "PUT", endpoint: `/UpdateArticle/${params.documentId}`, data, }); } /** * Update article fields in the database. * * This endpoint can only be used with articles that were assigned a documentId * when analysing with getAiTopics(). Only fields provided in the request * will be updated. Returns the updated article with all fields. * * @returns Article object with all updated fields * @throws {ValidationError} If parameters are invalid * @throws {AuthenticationError} If token is invalid * @throws {ForbiddenError} If token lacks permissions * @throws {NeuwoAPIError} For other API errors */ async updateArticle(params) { const response = await this.updateArticleRaw({ ...params, format: "json", }); const data = await (0, utils_js_1.parseJsonResponse)(response); const article = models_js_1.Article.fromApiResponse(data); logger_js_1.logger.info(`Successfully updated article: ${params.documentId}`); return article; } /** * Save training tags for an article (raw response). * * Returns the raw HTTP response without parsing. * * @returns Raw HTTP Response object * @throws {ValidationError} If tags array is empty or invalid * @throws {AuthenticationError} If token is invalid * @throws {ForbiddenError} If token lacks permissions * @throws {NeuwoAPIError} For other API errors */ async trainAiTopicsRaw(params) { params.format || (params.format = "json"); if (!params.tags || !Array.isArray(params.tags) || params.tags.length === 0) { throw new errors_js_1.ValidationError("You must provide some training tag values"); } const data = { documentid: params.documentId, tags: params.tags, format: params.format, }; logger_js_1.logger.info(`Adding ${params.tags.length} training tags to article: ${params.documentId}`); return this.requestHandler.request({ method: "POST", endpoint: "/TrainAiTopics", data, }); } /** * Save training tags for an article. * * Saves a list of training tags for an article in the database. * Returns all newly added TrainingTags (tags that weren't already in the database). * If all tags already exist, returns an empty array. * * @returns Array of TrainingTag objects representing newly added tags * @throws {ValidationError} If tags array is empty or invalid * @throws {AuthenticationError} If token is invalid * @throws {ForbiddenError} If token lacks permissions * @throws {NeuwoAPIError} For other API errors */ async trainAiTopics(params) { const response = await this.trainAiTopicsRaw({ ...params, format: "json", }); const data = await (0, utils_js_1.parseJsonResponse)(response); if (!Array.isArray(data)) { logger_js_1.logger.warning(`Expected array response, got: ${typeof data}`); return []; } const trainingTags = data.map((item) => models_js_1.TrainingTag.fromApiResponse(item)); logger_js_1.logger.info(`Added ${trainingTags.length} new training tags`); return trainingTags; } } exports.NeuwoRestClient = NeuwoRestClient; NeuwoRestClient.DEFAULT_TIMEOUT = 60; //# sourceMappingURL=rest-client.js.map