Skip to content
Snippets Groups Projects
Commit 819f6d85 authored by Taha Cherfia's avatar Taha Cherfia
Browse files

Merge branch 'main' into 'production'

Merge 'main into 'production'

See merge request app/holi-translation-api!3
parents 2be3d443 eb826c3a
Branches
Tags
No related merge requests found
export HOLI_LIBRETRANSLATE_BASE_URL=http://localhost:5000 export HOLI_LIBRETRANSLATE_BASE_URL=http://localhost:5000
export REDIS_HOST=localhost
export REDIS_PORT=6380
export REDIS_PASSWORD=
export REDIS_DB=
...@@ -151,8 +151,14 @@ if "you know what you're doing". ...@@ -151,8 +151,14 @@ if "you know what you're doing".
### Configuration ### Configuration
To run it locally, use the same Redis environment variables as those used by your local `unified-api` or `okuna`.
| Environment Variable | Default Value | Description | | Environment Variable | Default Value | Description |
| ---------------------------- | ------------- | ----------------------------------------------| | ---------------------------- | ------------- | --------------------------------------------- |
| PORT | 8089 | the port to listen on | | PORT | 8089 | the port to listen on |
| CACHE_ENABLED | true | wether or not to enable caching | | CACHE_ENABLED | true | wether or not to enable caching |
| CACHE_TTL_MS_LIBRE_TRANSLATE | 60 seconds | time-to-live in ms for libretranslate caching | | CACHE_TTL_MS_LIBRE_TRANSLATE | 60 seconds | time-to-live in ms for libretranslate caching |
| REDIS_HOST | localhost | the hostname of the Redis server |
| REDIS_PORT | 6380 | the port number of the Redis server |
| REDIS_PASSWORD | - | the password for the Redis server |
| REDIS_DB | - | the Redis database number to use |
...@@ -3,3 +3,4 @@ export { createSchema, createYoga } from "npm:graphql-yoga@5.0.1"; ...@@ -3,3 +3,4 @@ export { createSchema, createYoga } from "npm:graphql-yoga@5.0.1";
export { useResponseCache } from "npm:@graphql-yoga/plugin-response-cache@1.0.0"; export { useResponseCache } from "npm:@graphql-yoga/plugin-response-cache@1.0.0";
export { GraphQLError } from "npm:graphql@16.8.1"; export { GraphQLError } from "npm:graphql@16.8.1";
export { Parser } from "https://deno.land/x/html_parser@v0.1.3/src/mod.ts"; export { Parser } from "https://deno.land/x/html_parser@v0.1.3/src/mod.ts";
export { createHash } from "https://deno.land/std@0.129.0/hash/mod.ts";
...@@ -8,7 +8,8 @@ import { ...@@ -8,7 +8,8 @@ import {
ApiTranslationReslut, ApiTranslationReslut,
} from "./api_types.ts"; } from "./api_types.ts";
import { logger } from "./logging.ts"; import { logger } from "./logging.ts";
import { GraphQLError } from "./deps.ts"; import { client } from "./redis.ts";
import { createHash, GraphQLError } from "./deps.ts";
const BASE_URL = Deno.env.get("HOLI_LIBRETRANSLATE_BASE_URL"); const BASE_URL = Deno.env.get("HOLI_LIBRETRANSLATE_BASE_URL");
...@@ -31,6 +32,17 @@ const transformLanguageDetectionResult = ( ...@@ -31,6 +32,17 @@ const transformLanguageDetectionResult = (
export const translate = async ( export const translate = async (
query: TranslationQueryParameters, query: TranslationQueryParameters,
): Promise<string> => { ): Promise<string> => {
const cacheKey = createHash("sha256").update(
`translate:${query.text}:${query.targetLanguage}`,
).toString();
const cachedResult = await client.get(cacheKey);
if (cachedResult) {
logger.debug(`cache hit: ${JSON.stringify({ key: cacheKey })}`);
return cachedResult;
}
const url = `${BASE_URL}/translate`; const url = `${BASE_URL}/translate`;
logger.info(`Starting translation...`); logger.info(`Starting translation...`);
const start = Date.now(); const start = Date.now();
...@@ -42,7 +54,6 @@ export const translate = async ( ...@@ -42,7 +54,6 @@ export const translate = async (
source: "auto", source: "auto",
target: query.targetLanguage, target: query.targetLanguage,
format: TranslationFormat.TEXT, format: TranslationFormat.TEXT,
api_key: "",
}), }),
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
}); });
...@@ -50,10 +61,19 @@ export const translate = async ( ...@@ -50,10 +61,19 @@ export const translate = async (
throw new GraphQLError("Translation failed"); throw new GraphQLError("Translation failed");
} }
const json = await response.json(); const json = await response.json();
return transformTranslationResult(json); const result = transformTranslationResult(json);
await client.set(cacheKey, result);
return result;
} catch (e) { } catch (e) {
logger.error( logger.error(
`Error performing request to ${url}: ${e.message}`, `Error performing request to ${url}: ${
JSON.stringify({
message: e.message,
cause: e.cause,
})
}`,
); );
throw e; throw e;
} finally { } finally {
...@@ -73,7 +93,6 @@ export const detectLanguage = async ( ...@@ -73,7 +93,6 @@ export const detectLanguage = async (
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
q: query.text, q: query.text,
api_key: "",
}), }),
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
}); });
...@@ -84,10 +103,12 @@ export const detectLanguage = async ( ...@@ -84,10 +103,12 @@ export const detectLanguage = async (
return transformLanguageDetectionResult(json); return transformLanguageDetectionResult(json);
} catch (e) { } catch (e) {
logger.error( logger.error(
`Error performing request to ${url}: ${e.message}`, `Error performing request to ${url}: ${
); JSON.stringify({
logger.error( message: e.message,
`Error performing request to ${url}: ${e.cause}`, cause: e.cause,
})
}`,
); );
throw e; throw e;
} finally { } finally {
......
import { createClient } from "npm:redis@^4.6";
const missingEnvVars = [];
const REDIS_HOST = Deno.env.get("REDIS_HOST");
const REDIS_PORT = Deno.env.get("REDIS_PORT");
const REDIS_PASSWORD = Deno.env.get("REDIS_PASSWORD");
const REDIS_DB = Deno.env.get("REDIS_DB");
if (!REDIS_HOST) missingEnvVars.push("REDIS_HOST");
if (!REDIS_PORT) missingEnvVars.push("REDIS_PORT");
if (!REDIS_PASSWORD) missingEnvVars.push("REDIS_PASSWORD");
if (!REDIS_DB) missingEnvVars.push("REDIS_DB");
if (missingEnvVars.length > 0) {
throw new Error(
`The following Redis environment variables are missing: ${
missingEnvVars.join(", ")
}`,
);
}
export const client = await createClient({
socket: {
host: REDIS_HOST,
port: parseInt(REDIS_PORT),
},
password: REDIS_PASSWORD,
database: parseInt(REDIS_DB),
}).connect();
This diff is collapsed.
...@@ -4,6 +4,13 @@ resource "google_service_account" "translation_api" { ...@@ -4,6 +4,13 @@ resource "google_service_account" "translation_api" {
display_name = "Translation API service account for Cloud Run" display_name = "Translation API service account for Cloud Run"
} }
resource "google_project_iam_member" "translation_api" {
project = data.terraform_remote_state.holi_infra_state.outputs.shared_project_id
member = "serviceAccount:${google_service_account.translation_api.email}"
role = "roles/secretmanager.secretAccessor"
}
output "cloud_run_service_account_email" { output "cloud_run_service_account_email" {
value = google_service_account.translation_api.email value = google_service_account.translation_api.email
} }
...@@ -47,6 +47,29 @@ resource "google_cloud_run_v2_service" "translation_api_service" { ...@@ -47,6 +47,29 @@ resource "google_cloud_run_v2_service" "translation_api_service" {
value = local.environment == "production" ? "https://production.libretranslate.apis.holi.social" : "https://staging.libretranslate.apis.holi.social" value = local.environment == "production" ? "https://production.libretranslate.apis.holi.social" : "https://staging.libretranslate.apis.holi.social"
} }
env {
name = "REDIS_HOST"
value = data.terraform_remote_state.holi_infra_state.outputs.redis_host_cmek_development
}
env {
name = "REDIS_PORT"
value = data.terraform_remote_state.holi_infra_state.outputs.redis_port_cmek_development
}
env {
name = "REDIS_PASSWORD"
value_source {
secret_key_ref {
secret = "REDIS_CMEK_PASSWORD"
version = "latest"
}
}
}
env {
name = "REDIS_DB"
value = local.environment == "production" ? "13" : "5"
}
resources { resources {
limits = { limits = {
cpu = "1" cpu = "1"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment