@xuda.io/ai_module 1.1.5613 → 1.1.5614
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.mjs +94 -7
- package/index_ms.mjs +4 -0
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -9178,6 +9178,78 @@ export const is_spam_email = async function (uid, email, subject, account_profil
|
|
|
9178
9178
|
} catch (error) {}
|
|
9179
9179
|
};
|
|
9180
9180
|
|
|
9181
|
+
// AI screening for a marketplace publish. Receives plain-JSON context from
|
|
9182
|
+
// marketplace_module (zod schemas cannot cross the broker, so the prompt +
|
|
9183
|
+
// structured schema must live here). Returns a structured verdict across the
|
|
9184
|
+
// approval rule dimensions. The caller (marketplace_approval_review) merges
|
|
9185
|
+
// this with deterministic account-standing checks and decides the final stat.
|
|
9186
|
+
export const marketplace_review_item = async function (req) {
|
|
9187
|
+
const { uid, item_type, item = {}, account_context = {}, account_name = '', model = _conf.default_ai_model, account_profile_info } = req || {};
|
|
9188
|
+
|
|
9189
|
+
const check_schema = z.object({
|
|
9190
|
+
flag: z.boolean().describe('true if this concern is present'),
|
|
9191
|
+
severity: z.enum(['none', 'low', 'medium', 'high']).describe('how serious the concern is'),
|
|
9192
|
+
note: z.string().describe('one short sentence of evidence; empty string if no concern'),
|
|
9193
|
+
});
|
|
9194
|
+
|
|
9195
|
+
const response_format = z.object({
|
|
9196
|
+
decision: z.enum(['approve', 'reject', 'manual_review']).describe('approve = safe to publish; reject = clear violation; manual_review = uncertain, needs a human'),
|
|
9197
|
+
confidence: z.number().min(0).max(100).describe('confidence in the decision, 0-100'),
|
|
9198
|
+
checks: z.object({
|
|
9199
|
+
ai_bot_activity: check_schema.describe('automated/bot publishing: high velocity, near-duplicate items, low-effort generated bulk'),
|
|
9200
|
+
commercial_undisclosed: check_schema.describe('undisclosed commercial intent: external paid links, lead-gen, off-platform payment, advertising inconsistent with declared price/category'),
|
|
9201
|
+
harmful_code: check_schema.describe('destructive ops, data exfiltration, crypto-miners, obfuscation, malicious network calls in the submitted code'),
|
|
9202
|
+
suspicious_activity: check_schema.describe('mismatched metadata, hidden payloads, evasion patterns'),
|
|
9203
|
+
malformed_account_name: check_schema.describe('gibberish, homoglyphs, embedded URLs, or impersonation in the account name'),
|
|
9204
|
+
spam_low_quality: check_schema.describe('spam, filler, or low-quality content with no real utility'),
|
|
9205
|
+
impersonation_trademark: check_schema.describe('impersonates a brand/person or abuses a trademark'),
|
|
9206
|
+
prohibited_content: check_schema.describe('adult, illegal, hateful, or otherwise disallowed content'),
|
|
9207
|
+
plagiarism_duplicate: check_schema.describe('appears copied from or duplicates an existing item'),
|
|
9208
|
+
secrets_pii_leak: check_schema.describe('hardcoded API keys, tokens, credentials, or exposed PII in the code'),
|
|
9209
|
+
}),
|
|
9210
|
+
reasons: z.array(z.string()).describe('short user-facing lines explaining the decision (empty if approved cleanly)'),
|
|
9211
|
+
});
|
|
9212
|
+
|
|
9213
|
+
const prompt = `You are the xuda marketplace moderation reviewer. Decide whether the following ${item_type} should be published to the public marketplace.
|
|
9214
|
+
|
|
9215
|
+
Account name: ${account_name}
|
|
9216
|
+
Account context (signals): ${JSON.stringify(account_context)}
|
|
9217
|
+
|
|
9218
|
+
Item:
|
|
9219
|
+
- name: ${item.name || ''}
|
|
9220
|
+
- description: ${item.description || ''}
|
|
9221
|
+
- category: ${item.category || ''}
|
|
9222
|
+
- tags: ${JSON.stringify(item.tags || [])}
|
|
9223
|
+
- price: ${item.price ?? 0}
|
|
9224
|
+
- code/content summary: ${item.code_summary || '(none provided)'}
|
|
9225
|
+
|
|
9226
|
+
Evaluate every check honestly. Set decision to:
|
|
9227
|
+
- "approve" when no medium/high concerns and the item is genuine and useful.
|
|
9228
|
+
- "reject" when there is a clear high-severity violation (harmful code, leaked secrets, prohibited content, obvious impersonation/spam, or clear bot abuse).
|
|
9229
|
+
- "manual_review" when concerns are present but ambiguous, or you are not confident.
|
|
9230
|
+
Keep "reasons" concise, factual, and user-facing (no internal jargon).`;
|
|
9231
|
+
|
|
9232
|
+
const ret = await submit_chat_gpt_prompt({
|
|
9233
|
+
uid,
|
|
9234
|
+
prompt,
|
|
9235
|
+
model,
|
|
9236
|
+
response_format,
|
|
9237
|
+
metadata: { func: 'marketplace_review_item', item_type },
|
|
9238
|
+
account_profile_info,
|
|
9239
|
+
});
|
|
9240
|
+
|
|
9241
|
+
if (ret.code < 0) {
|
|
9242
|
+
return { code: ret.code, data: ret.data };
|
|
9243
|
+
}
|
|
9244
|
+
|
|
9245
|
+
try {
|
|
9246
|
+
const verdict = JSON.parse(ret.data);
|
|
9247
|
+
return { code: 1, data: { ...verdict, model } };
|
|
9248
|
+
} catch (err) {
|
|
9249
|
+
return { code: -1, data: `marketplace_review_item parse error: ${err.message}` };
|
|
9250
|
+
}
|
|
9251
|
+
};
|
|
9252
|
+
|
|
9181
9253
|
export const is_business_contact = async function (uid, email, name, subject, body, account_profile_info) {
|
|
9182
9254
|
let prompt = `detect if the email "${email}", subject "${subject}", name "${name}", or body "${body}" is business or personal. Return true if it is a business , false otherwise.
|
|
9183
9255
|
|
|
@@ -14256,7 +14328,7 @@ export const get_widget_embed_snippet = async function (req, job_id, headers) {
|
|
|
14256
14328
|
};
|
|
14257
14329
|
|
|
14258
14330
|
const _widget_signup_core = async function (req, job_id, headers, opts) {
|
|
14259
|
-
const { profile_id, email, name, widget_origin, google_sub, signup_method } = req;
|
|
14331
|
+
const { profile_id, email, name, widget_origin, google_sub, signup_method, visitor_lang } = req;
|
|
14260
14332
|
const [owner_uid_part, pid_part] = String(profile_id || '').split('.');
|
|
14261
14333
|
if (!owner_uid_part || !pid_part) return { code: -404, data: 'invalid_profile' };
|
|
14262
14334
|
|
|
@@ -14268,19 +14340,19 @@ const _widget_signup_core = async function (req, job_id, headers, opts) {
|
|
|
14268
14340
|
if (ap_doc.widget_enabled === false) return { code: -404, data: 'widget_disabled' };
|
|
14269
14341
|
|
|
14270
14342
|
const visitor_uid = await _widget_find_or_create_visitor(email, name, google_sub);
|
|
14271
|
-
return await _widget_signup_finalize(visitor_uid, email, name, widget_origin, signup_method, account_profile_info, canonical_owner_uid, canonical_profile_id, ap_doc, job_id, headers);
|
|
14343
|
+
return await _widget_signup_finalize(visitor_uid, email, name, widget_origin, signup_method, account_profile_info, canonical_owner_uid, canonical_profile_id, ap_doc, job_id, headers, visitor_lang);
|
|
14272
14344
|
};
|
|
14273
14345
|
|
|
14274
14346
|
export const widget_signup = async function (req, job_id, headers) {
|
|
14275
14347
|
try {
|
|
14276
|
-
let { profile_id, email, name, widget_origin } = req;
|
|
14348
|
+
let { profile_id, email, name, widget_origin, visitor_lang } = req;
|
|
14277
14349
|
if (typeof email !== 'string' || typeof name !== 'string') return { code: -1, data: 'invalid_input' };
|
|
14278
14350
|
email = email.toLowerCase().trim();
|
|
14279
14351
|
name = name.trim();
|
|
14280
14352
|
if (!email || !name) return { code: -1, data: 'invalid_input' };
|
|
14281
14353
|
if (!WIDGET_EMAIL_RE.test(email)) return { code: -1, data: 'invalid_email' };
|
|
14282
14354
|
|
|
14283
|
-
return await _widget_signup_core({ profile_id, email, name, widget_origin, signup_method: 'email' }, job_id, headers);
|
|
14355
|
+
return await _widget_signup_core({ profile_id, email, name, widget_origin, visitor_lang, signup_method: 'email' }, job_id, headers);
|
|
14284
14356
|
} catch (err) {
|
|
14285
14357
|
return { code: -1, data: err.message || String(err) };
|
|
14286
14358
|
}
|
|
@@ -14288,7 +14360,7 @@ export const widget_signup = async function (req, job_id, headers) {
|
|
|
14288
14360
|
|
|
14289
14361
|
export const widget_signup_google = async function (req, job_id, headers) {
|
|
14290
14362
|
try {
|
|
14291
|
-
const { profile_id, id_token, widget_origin } = req;
|
|
14363
|
+
const { profile_id, id_token, widget_origin, visitor_lang } = req;
|
|
14292
14364
|
if (!id_token || typeof id_token !== 'string') return { code: -1, data: 'missing_id_token' };
|
|
14293
14365
|
|
|
14294
14366
|
let payload;
|
|
@@ -14304,13 +14376,13 @@ export const widget_signup_google = async function (req, job_id, headers) {
|
|
|
14304
14376
|
const name = String(payload.name || payload.email?.split('@')[0] || 'Friend').trim();
|
|
14305
14377
|
if (!email) return { code: -1, data: 'no_email_in_token' };
|
|
14306
14378
|
|
|
14307
|
-
return await _widget_signup_core({ profile_id, email, name, widget_origin, google_sub: payload.sub, signup_method: 'google' }, job_id, headers);
|
|
14379
|
+
return await _widget_signup_core({ profile_id, email, name, widget_origin, visitor_lang, google_sub: payload.sub, signup_method: 'google' }, job_id, headers);
|
|
14308
14380
|
} catch (err) {
|
|
14309
14381
|
return { code: -1, data: err.message || String(err) };
|
|
14310
14382
|
}
|
|
14311
14383
|
};
|
|
14312
14384
|
|
|
14313
|
-
const _widget_signup_finalize = async function (visitor_uid, email, name, widget_origin, signup_method, account_profile_info, canonical_owner_uid, canonical_profile_id, ap_doc, job_id, headers) {
|
|
14385
|
+
const _widget_signup_finalize = async function (visitor_uid, email, name, widget_origin, signup_method, account_profile_info, canonical_owner_uid, canonical_profile_id, ap_doc, job_id, headers, visitor_lang) {
|
|
14314
14386
|
try {
|
|
14315
14387
|
let team_req_doc = await _widget_find_existing_team_req(visitor_uid, canonical_profile_id);
|
|
14316
14388
|
let assigned_uid;
|
|
@@ -14374,12 +14446,20 @@ const _widget_signup_finalize = async function (visitor_uid, email, name, widget
|
|
|
14374
14446
|
|
|
14375
14447
|
const widget_token = `wds_${crypto.randomUUID().replace(/-/g, '')}`;
|
|
14376
14448
|
const now = Date.now();
|
|
14449
|
+
// Normalize visitor_lang to a short tag (e.g. "ja-JP" → "ja"). The
|
|
14450
|
+
// auto-reply agent reads this from the session to respond in the
|
|
14451
|
+
// visitor's language. Empty / missing → English fallback at reply time.
|
|
14452
|
+
const visitor_lang_base = String(visitor_lang || '')
|
|
14453
|
+
.toLowerCase()
|
|
14454
|
+
.split('-')[0]
|
|
14455
|
+
.slice(0, 8);
|
|
14377
14456
|
const session_doc = {
|
|
14378
14457
|
_id: widget_token,
|
|
14379
14458
|
docType: 'widget_session',
|
|
14380
14459
|
stat: 2,
|
|
14381
14460
|
state,
|
|
14382
14461
|
visitor_uid,
|
|
14462
|
+
visitor_lang: visitor_lang_base || '',
|
|
14383
14463
|
team_req_id: team_req_doc._id,
|
|
14384
14464
|
assigned_uid,
|
|
14385
14465
|
owner_uid: canonical_owner_uid,
|
|
@@ -14398,6 +14478,12 @@ const _widget_signup_finalize = async function (visitor_uid, email, name, widget
|
|
|
14398
14478
|
const assigned_avatar = assigned_info_ret?.data?.profile_picture || assigned_info_ret?.data?.profile_avatar || '';
|
|
14399
14479
|
const greeting = ap_doc?.widget_config?.greeting || WIDGET_DEFAULT_GREETING;
|
|
14400
14480
|
|
|
14481
|
+
// Surface the visitor's first name so the chat widget can personalize the
|
|
14482
|
+
// greeting on the page ("Hi {visitor_first_name}, I'm Valentina..."). The
|
|
14483
|
+
// widget reads this from the persisted session and replaces the
|
|
14484
|
+
// {visitor_name} placeholder client-side.
|
|
14485
|
+
const visitor_first_name = _widget_split_name(name).first_name || '';
|
|
14486
|
+
|
|
14401
14487
|
return {
|
|
14402
14488
|
code: 1,
|
|
14403
14489
|
data: {
|
|
@@ -14407,6 +14493,7 @@ const _widget_signup_finalize = async function (visitor_uid, email, name, widget
|
|
|
14407
14493
|
assigned_avatar,
|
|
14408
14494
|
greeting,
|
|
14409
14495
|
conversation_id,
|
|
14496
|
+
visitor_first_name,
|
|
14410
14497
|
signup_method: signup_method || 'email',
|
|
14411
14498
|
account_active: signup_method === 'google',
|
|
14412
14499
|
signin_url: signup_method === 'google' ? `https://${_conf.domain || 'xuda.ai'}/dashboard/login` : undefined,
|
package/index_ms.mjs
CHANGED
|
@@ -260,3 +260,7 @@ export const widget_send_message = async function (...args) {
|
|
|
260
260
|
export const widget_get_messages = async function (...args) {
|
|
261
261
|
return await broker.send_to_queue("widget_get_messages", ...args);
|
|
262
262
|
};
|
|
263
|
+
|
|
264
|
+
export const marketplace_review_item = async function (...args) {
|
|
265
|
+
return await broker.send_to_queue("marketplace_review_item", ...args);
|
|
266
|
+
};
|