Merge branch 'main' into feature/issue-#975/finish-French-translations

This commit is contained in:
Nariman Jelveh
2024-12-12 07:42:45 -08:00
committed by GitHub
7 changed files with 147 additions and 33 deletions
@@ -6,6 +6,7 @@ const { DB_WRITE } = require("../../services/database/consts");
const { TypeSpec } = require("../../services/drivers/meta/Construct");
const { TypedValue } = require("../../services/drivers/meta/Runtime");
const { Context } = require("../../util/context");
const { AsModeration } = require("./lib/AsModeration");
// Maximum number of fallback attempts when a model fails, including the first attempt
const MAX_FALLBACKS = 3 + 1; // includes first attempt
@@ -278,6 +279,7 @@ class AIChatService extends BaseService {
intended_service,
parameters
};
await svc_event.emit('ai.prompt.validate', event);
if ( ! event.allow ) {
test_mode = true;
}
@@ -489,11 +491,6 @@ class AIChatService extends BaseService {
* Returns true if OpenAI service is unavailable or all messages pass moderation.
*/
async moderate ({ messages }) {
const svc_openai = this.services.get('openai-completion');
// We can't use moderation of openai service isn't available
if ( ! svc_openai ) return true;
for ( const msg of messages ) {
const texts = [];
if ( typeof msg.content === 'string' ) texts.push(msg.content);
@@ -508,8 +505,41 @@ class AIChatService extends BaseService {
const fulltext = texts.join('\n');
const mod_result = await svc_openai.check_moderation(fulltext);
if ( mod_result.flagged ) return false;
let mod_last_error = null;
let mod_result = null;
try {
const svc_openai = this.services.get('openai-completion');
mod_result = await svc_openai.check_moderation(fulltext);
if ( mod_result.flagged ) return false;
continue;
} catch (e) {
console.error(e);
mod_last_error = e;
}
try {
const svc_claude = this.services.get('claude');
const chat = svc_claude.as('puter-chat-completion');
const mod = new AsModeration({
chat,
model: 'claude-3-haiku-20240307',
})
if ( ! await mod.moderate(fulltext) ) {
return false;
}
mod_last_error = null;
continue;
} catch (e) {
console.error(e);
mod_last_error = e;
}
if ( mod_last_error ) {
this.log.error('moderation error', {
fulltext,
mod_last_error,
});
throw new Error('no working moderation service');
}
}
return true;
}
@@ -65,6 +65,10 @@ class FakeChatService extends BaseService {
"output_tokens": 1
}
},
"usage": {
"input_tokens": 0,
"output_tokens": 1
},
"logprobs": null,
"finish_reason": "stop"
}
@@ -0,0 +1,77 @@
const { default: dedent } = require("dedent");
class AsModeration {
constructor ({ chat, model }) {
this.chat = chat;
this.model = model;
}
async moderate (text) {
// copied from Anthropic documentation
// https://docs.anthropic.com/en/docs/about-claude/use-case-guides/content-moderation
const unsafe_categories = [
'Child Exploitation',
'Conspiracy Theories',
'Hate',
'Indiscriminate Weapons',
'Intellectual Property',
'Non-Violent Crimes',
'Privacy',
'Self-Harm',
'Sex Crimes',
'Sexual Content',
'Specialized Advice',
'Violent Crimes'
];
const unsafe_category_str = unsafe_categories.join('\n');
const assessment_prompt = dedent(`
Determine whether the following message warrants moderation,
based on the unsafe categories outlined below.
Message:
<message>
${text
.replace('<', '&lt;')
.replace('>', '&gt;')
}
</message>
Unsafe Categories:
<categories>
${unsafe_category_str}
</categories>
Respond with ONLY a JSON object, using the format below:
{{
"violation": <Boolean field denoting whether the message should be moderated>,
"categories": [Comma-separated list of violated categories],
"explanation": [Optional. Only include if there is a violation.]
}}
`);
const result = await this.chat.complete({
messages: [
{
role: 'user',
content: assessment_prompt,
}
]
});
console.log('result???', require('util').inspect(result, { depth: null }));
const str = result.message?.content?.[0]?.text ??
result.messages?.[0]?.content?.[0]?.text ??
'{ "violation": true }';
const parsed = JSON.parse(str);
console.log('parsed?', parsed);
return ! parsed.violation;
}
}
module.exports = {
AsModeration,
};
+1 -1
View File
@@ -169,7 +169,7 @@
<!---------------------------------------->
<!-- Edit App -->
<!---------------------------------------->
<section id="edit-app">
<section id="edit-app" style="margin-bottom: 100px;">
</section>
<!---------------------------------------->
+8 -5
View File
@@ -518,9 +518,11 @@ function generate_edit_app_section(app) {
</div>
<div class="section-tab" data-tab="info">
<form style="clear:both;">
<form style="clear:both; padding-bottom: 50px;">
<div class="error" id="edit-app-error"></div>
<div class="success" id="edit-app-success">App has been successfully updated.<span class="close-success-msg">&times;</span></div>
<div class="success" id="edit-app-success">App has been successfully updated.<span class="close-success-msg">&times;</span>
<p style="margin-bottom:0;"><span class="open-app button button-action" data-uid="${html_encode(app.uid)}" data-app-name="${html_encode(app.name)}">Give it a try!</span></p>
</div>
<input type="hidden" id="edit-app-uid" value="${html_encode(app.uid)}">
<h3 style="font-size: 23px; border-bottom: 1px solid #EEE; margin-top: 40px;">Basic</h3>
@@ -612,9 +614,10 @@ function generate_edit_app_section(app) {
<p><code>credentialless</code> attribute for the <code>iframe</code> tag.</p>
</div>
<hr style="margin-top: 40px;">
<button type="button" class="edit-app-save-btn button button-primary">Save</button>
<button type="button" class="edit-app-reset-btn button button-secondary">Reset</button>
<div style="box-shadow: 10px 10px 15px #8c8c8c; overflow: hidden; position: fixed; bottom: 0; background: white; padding: 10px; width: 100%; left: 0;">
<button type="button" class="edit-app-save-btn button button-primary" style="margin-right: 40px;">Save</button>
<button type="button" class="edit-app-reset-btn button button-secondary">Reset</button>
</div>
</form>
</div>
`
+19 -20
View File
@@ -364,21 +364,21 @@ const fr = {
"This user already has access to this item": 'Cet utilisateur à déja accès à cet élément',
// ----------------------------------------
// Missing translations:
// translations:
// ----------------------------------------
"billing.change_payment_method": "Modifier", // In English: "Change"
"billing.change_payment_method": "Modifier le mode de paiement", // In English: "Change"
"billing.cancel": "Annuler", // In English: "Cancel"
"billing.download_invoice": "Télécharger la facture", // In English: "Download"
"billing.payment_method": "Méthode de paiement", // In English: "Payment Method"
"billing.payment_method_updated": "Méthode de paiement mise à jour !", // In English: "Payment method updated!"
"billing.confirm_payment_method": "Confirmer la méthode de paiement", // In English: "Confirm Payment Method"
"billing.payment_method": "Mode de paiement", // In English: "Payment Method"
"billing.payment_method_updated": "Mode de paiement mis à jour !", // In English: "Payment method updated!"
"billing.confirm_payment_method": "Confirmer le mode de paiement", // In English: "Confirm Payment Method"
"billing.payment_history": "Historique des paiements", // In English: "Payment History"
"billing.refunded": "Remboursé", // In English: "Refunded"
"billing.paid": "Payé", // In English: "Paid"
"billing.ok": "OK", // In English: "OK"
"billing.resume_subscription": "Reprendre l'abonnement", // In English: "Resume Subscription"
"billing.subscription_cancelled": "Votre abonnement a été annulé.", // In English: "Your subscription has been canceled."
"billing.subscription_cancelled_description": "Vous conserverez l'accès à votre abonnement jusqu'à la fin de cette période de facturation.", // In English: "You will still have access to your subscription until the end of this billing period."
"billing.subscription_cancelled_description": "Vous aurez toujours accès à votre abonnement jusqu'à la fin de cette période de facturation.", // In English: "You will still have access to your subscription until the end of this billing period."
"billing.offering.free": "Gratuit", // In English: "Free"
"billing.offering.pro": "Professionnel", // In English: "Professional"
"billing.offering.business": "Entreprise", // In English: "Business"
@@ -386,24 +386,24 @@ const fr = {
"billing.ai_access": "Accès à l'IA", // In English: "AI Access"
"billing.bandwidth": "Bande passante", // In English: "Bandwidth"
"billing.apps_and_games": "Applications et jeux", // In English: "Apps & Games"
"billing.upgrade_to_pro": "Passer à la version %strong%", // In English: "Upgrade to %strong%"
"billing.switch_to": "Optez pour %strong%", // In English: "Switch to %strong%"
"billing.payment_setup": "Configuration des paiements", // In English: "Payment Setup"
"billing.upgrade_to_pro": "Passer à %strong%", // In English: "Upgrade to %strong%"
"billing.switch_to": "Passer à %strong%", // In English: "Switch to %strong%"
"billing.payment_setup": "Configuration du paiement", // In English: "Payment Setup"
"billing.back": "Retour", // In English: "Back"
"billing.you_are_now_subscribed_to": "Vous êtes désormais abonné au niveau %strong%.", // In English: "You are now subscribed to %strong% tier."
"billing.you_are_now_subscribed_to_without_tier": "Vous êtes désormais abonné", // In English: "You are now subscribed"
"billing.subscription_cancellation_confirmation": "Êtes-vous certain de vouloir annuler votre abonnement ?", // In English: "Are you sure you want to cancel your subscription?"
"billing.you_are_now_subscribed_to": "Vous êtes maintenant abonné au niveau %strong%.", // In English: "You are now subscribed to %strong% tier."
"billing.you_are_now_subscribed_to_without_tier": "Vous êtes maintenant abonné", // In English: "You are now subscribed"
"billing.subscription_cancellation_confirmation": "Êtes-vous sûr de vouloir annuler votre abonnement ?", // In English: "Are you sure you want to cancel your subscription?"
"billing.subscription_setup": "Configuration de l'abonnement", // In English: "Subscription Setup"
"billing.cancel_it": "Annuler", // In English: "Cancel It"
"billing.keep_it": "Conserver", // In English: "Keep It"
"billing.subscription_resumed": "Votre abonnement %strong% a été réactivé !", // In English: "Your %strong% subscription has been resumed!"
"billing.cancel_it": "L'annuler", // In English: "Cancel It"
"billing.keep_it": "Le conserver", // In English: "Keep It"
"billing.subscription_resumed": "Votre abonnement %strong% a été repris !", // In English: "Your %strong% subscription has been resumed!"
"billing.upgrade_now": "Mettre à niveau maintenant", // In English: "Upgrade Now"
"billing.upgrade": "Mettre à niveau", // In English: "Upgrade"
"billing.currently_on_free_plan": "Vous êtes actuellement sur le plan gratuit.", // In English: "You are currently on the free plan."
"billing.download_receipt": "Télécharger le reçu", // In English: "Download Receipt"
"billing.subscription_check_error": "Un problème est survenu lors de la vérification de votre abonnement.", // In English: "A problem occurred while checking your subscription status."
"billing.email_confirmation_needed": "Votre e-mail n'a pas été confirmé. Nous vous enverrons un code pour le confirmer maintenant.", // In English: "Your email has not been confirmed. We'll send you a code to confirm it now."
"billing.sub_cancelled_but_valid_until": "Vous avez annulé votre abonnement, mais il restera actif jusqu'à la fin de la période de facturation. Vous ne serez pas facturé à nouveau, sauf si vous vous réabonnez.", // In English: "You have cancelled your subscription and it will automatically switch to the free tier at the end of the billing period. You will not be charged again unless you re-subscribe."
"billing.subscription_check_error": "Un problème est survenu lors de la vérification de votre statut d'abonnement.", // In English: "A problem occurred while checking your subscription status."
"billing.email_confirmation_needed": "Votre e-mail n'a pas été confirmé. Nous allons vous envoyer un code pour le confirmer maintenant.", // In English: "Your email has not been confirmed. We'll send you a code to confirm it now."
"billing.sub_cancelled_but_valid_until": "Vous avez annulé votre abonnement et il passera automatiquement au niveau gratuit à la fin de la période de facturation. Vous ne serez pas facturé à nouveau sauf si vous vous réabonnez.", // In English: "You have cancelled your subscription and it will automatically switch to the free tier at the end of the billing period. You will not be charged again unless you re-subscribe."
"billing.current_plan_until_end_of_period": "Votre plan actuel jusqu'à la fin de cette période de facturation.", // In English: "Your current plan until the end of this billing period."
"billing.current_plan": "Plan actuel", // In English: "Current plan"
"billing.cancelled_subscription_tier": "Abonnement annulé (%%)", // In English: "Cancelled Subscription (%%)"
@@ -411,8 +411,7 @@ const fr = {
"billing.limited": "Limité", // In English: "Limited"
"billing.expanded": "Étendu", // In English: "Expanded"
"billing.accelerated": "Accéléré", // In English: "Accelerated"
"billing.enjoy_msg": "Profitez de %% de stockage cloud, ainsi que d'autres avantages." // In English: "Enjoy %% of Cloud Storage plus other benefits."
"billing.enjoy_msg": "Profitez de %% de stockage cloud et d'autres avantages.", // In English: "Enjoy %% of Cloud Storage plus other benefits."
}
};
+1
View File
@@ -435,6 +435,7 @@ const ko = {
"billing.current_plan_until_end_of_period":
"청구 기간이 끝날 때까지 유지되는 현재 플랜입니다.", // In English: "Your current plan until the end of this billing period."
"billing.current_plan": "현재 플랜", // In English: "Current plan" ; depending on the context you could use: "구독 중인 플랜" (plan you are subscribed to)
"billing.cancelled_subscription_tier": "취소된 구독 (%%)", // In English: "Cancelled Subscription (%%)"
"billing.manage": "관리", // In English: "Manage"
"billing.limited": "제한됨", // In English: "Limited"