mirror of
https://github.com/documenso/documenso.git
synced 2025-11-19 19:21:39 +10:00
fix: email place holder
This commit is contained in:
@ -9,31 +9,6 @@ export type AiRecipient = {
|
|||||||
signingOrder?: number;
|
signingOrder?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sanitizeEmailLocalPart = (value: string) => {
|
|
||||||
return value
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/[^a-z0-9]+/g, '.')
|
|
||||||
.replace(/\.+/g, '.')
|
|
||||||
.replace(/^\.+|\.+$/g, '')
|
|
||||||
.slice(0, 32);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createPlaceholderRecipientEmail = (
|
|
||||||
name: string,
|
|
||||||
envelopeId: string,
|
|
||||||
position: number,
|
|
||||||
) => {
|
|
||||||
const normalizedName = sanitizeEmailLocalPart(name);
|
|
||||||
const baseLocalPart = normalizedName ? `${normalizedName}.${position}` : `recipient-${position}`;
|
|
||||||
const envelopeSuffix = envelopeId
|
|
||||||
.replace(/[^a-z0-9]/gi, '')
|
|
||||||
.toLowerCase()
|
|
||||||
.slice(0, 6);
|
|
||||||
const suffix = envelopeSuffix ? `-${envelopeSuffix}` : '';
|
|
||||||
|
|
||||||
return `${baseLocalPart}${suffix}@documenso.ai`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const analyzeRecipientsFromDocument = async (envelopeId: string): Promise<AiRecipient[]> => {
|
export const analyzeRecipientsFromDocument = async (envelopeId: string): Promise<AiRecipient[]> => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/ai/analyze-recipients', {
|
const response = await fetch('/api/ai/analyze-recipients', {
|
||||||
@ -65,7 +40,6 @@ export const ensureRecipientEmails = (
|
|||||||
recipients: AiRecipient[],
|
recipients: AiRecipient[],
|
||||||
envelopeId: string,
|
envelopeId: string,
|
||||||
): RecipientForCreation[] => {
|
): RecipientForCreation[] => {
|
||||||
let recipientIndex = 1;
|
|
||||||
const allowedRoles: RecipientRole[] = [
|
const allowedRoles: RecipientRole[] = [
|
||||||
RecipientRole.SIGNER,
|
RecipientRole.SIGNER,
|
||||||
RecipientRole.APPROVER,
|
RecipientRole.APPROVER,
|
||||||
@ -73,11 +47,7 @@ export const ensureRecipientEmails = (
|
|||||||
];
|
];
|
||||||
|
|
||||||
return recipients.map((recipient) => {
|
return recipients.map((recipient) => {
|
||||||
const email =
|
const email = recipient.email ?? '';
|
||||||
recipient.email ??
|
|
||||||
createPlaceholderRecipientEmail(recipient.name, envelopeId, recipientIndex);
|
|
||||||
|
|
||||||
recipientIndex += 1;
|
|
||||||
|
|
||||||
const candidateRole = recipient.role as RecipientRole;
|
const candidateRole = recipient.role as RecipientRole;
|
||||||
const normalizedRole = allowedRoles.includes(candidateRole)
|
const normalizedRole = allowedRoles.includes(candidateRole)
|
||||||
|
|||||||
@ -227,7 +227,7 @@ const runFormFieldDetection = async (
|
|||||||
const prompt = buildFieldDetectionPrompt(recipients);
|
const prompt = buildFieldDetectionPrompt(recipients);
|
||||||
|
|
||||||
const result = await generateObject({
|
const result = await generateObject({
|
||||||
model: 'google/gemini-2.5-pro',
|
model: 'google/gemini-3-pro-preview',
|
||||||
output: 'array',
|
output: 'array',
|
||||||
schema: ZDetectedFormFieldSchema,
|
schema: ZDetectedFormFieldSchema,
|
||||||
messages: [
|
messages: [
|
||||||
@ -284,33 +284,7 @@ const MAX_PAGES_FOR_RECIPIENT_ANALYSIS = 3;
|
|||||||
|
|
||||||
const recipientEmailSchema = z.string().email();
|
const recipientEmailSchema = z.string().email();
|
||||||
|
|
||||||
const sanitizeEmailLocalPart = (value: string) => {
|
const resolveRecipientEmail = (candidateEmail: string | undefined) => {
|
||||||
return value
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/[^a-z0-9]+/g, '.')
|
|
||||||
.replace(/\.+/g, '.')
|
|
||||||
.replace(/^\.+|\.+$/g, '')
|
|
||||||
.slice(0, 32);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createPlaceholderRecipientEmail = (name: string, envelopeId: string, position: number) => {
|
|
||||||
const normalizedName = sanitizeEmailLocalPart(name);
|
|
||||||
const baseLocalPart = normalizedName ? `${normalizedName}.${position}` : `recipient-${position}`;
|
|
||||||
const sanitizedEnvelopeSuffix = envelopeId
|
|
||||||
.replace(/[^a-z0-9]/gi, '')
|
|
||||||
.toLowerCase()
|
|
||||||
.slice(0, 6);
|
|
||||||
const suffix = sanitizedEnvelopeSuffix ? `-${sanitizedEnvelopeSuffix}` : '';
|
|
||||||
|
|
||||||
return `${baseLocalPart}${suffix}@documenso.ai`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const resolveRecipientEmail = (
|
|
||||||
candidateEmail: string | undefined,
|
|
||||||
name: string,
|
|
||||||
envelopeId: string,
|
|
||||||
position: number,
|
|
||||||
) => {
|
|
||||||
if (candidateEmail) {
|
if (candidateEmail) {
|
||||||
const trimmedEmail = candidateEmail.trim();
|
const trimmedEmail = candidateEmail.trim();
|
||||||
|
|
||||||
@ -319,7 +293,7 @@ const resolveRecipientEmail = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return createPlaceholderRecipientEmail(name, envelopeId, position);
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const authorizeDocumentAccess = async (envelopeId: string, userId: number) => {
|
const authorizeDocumentAccess = async (envelopeId: string, userId: number) => {
|
||||||
@ -388,13 +362,11 @@ EXTRACTION RULES:
|
|||||||
3. Look for "Approved by:", "Reviewed by:", "CC:" sections
|
3. Look for "Approved by:", "Reviewed by:", "CC:" sections
|
||||||
4. Extract FULL NAMES as they appear in the document
|
4. Extract FULL NAMES as they appear in the document
|
||||||
5. If an email address is visible near a name, include it exactly in the "email" field
|
5. If an email address is visible near a name, include it exactly in the "email" field
|
||||||
6. If NO email is found, create a realistic placeholder email using the person's name and the domain "documenso.ai" (e.g., john.doe@documenso.ai). Every recipient MUST have an email.
|
6. If NO email is found, leave the email field empty.
|
||||||
7. Ensure placeholder emails look unique when multiple people share the same name (append a number if needed)
|
7. Assign signing order based on document flow (numbered items, "First signer:", "Second signer:", or top-to-bottom sequence)
|
||||||
8. Assign signing order based on document flow (numbered items, "First signer:", "Second signer:", or top-to-bottom sequence)
|
|
||||||
|
|
||||||
IMPORTANT:
|
IMPORTANT:
|
||||||
- Only extract recipients explicitly mentioned in the document
|
- Only extract recipients explicitly mentioned in the document
|
||||||
- Email is mandatory for every recipient (real, sample, or placeholder derived from the document text)
|
|
||||||
- Default role is SIGNER if unclear (signature lines = SIGNER)
|
- Default role is SIGNER if unclear (signature lines = SIGNER)
|
||||||
- Signing order starts at 1 (first signer = 1, second = 2, etc.)
|
- Signing order starts at 1 (first signer = 1, second = 2, etc.)
|
||||||
- If no clear ordering, omit signingOrder
|
- If no clear ordering, omit signingOrder
|
||||||
@ -710,12 +682,7 @@ export const aiRoute = new Hono<HonoEnv>()
|
|||||||
const { pageNumber, recipients } = result.value;
|
const { pageNumber, recipients } = result.value;
|
||||||
|
|
||||||
const recipientsWithEmails = recipients.map((recipient) => {
|
const recipientsWithEmails = recipients.map((recipient) => {
|
||||||
const email = resolveRecipientEmail(
|
const email = resolveRecipientEmail(recipient.email);
|
||||||
recipient.email,
|
|
||||||
recipient.name,
|
|
||||||
envelopeId,
|
|
||||||
recipientIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
const normalizedRecipient: TDetectedRecipient = {
|
const normalizedRecipient: TDetectedRecipient = {
|
||||||
...recipient,
|
...recipient,
|
||||||
|
|||||||
@ -84,10 +84,7 @@ export const ZDetectedRecipientLLMSchema = createRecipientSchema(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const ZDetectedRecipientSchema = createRecipientSchema(
|
export const ZDetectedRecipientSchema = createRecipientSchema(
|
||||||
z
|
z.string().email().optional().describe('Email address for the recipient (if found in document).'),
|
||||||
.string()
|
|
||||||
.email()
|
|
||||||
.describe('Email address for the recipient (real, sample, or generated placeholder).'),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export const ZAnalyzeRecipientsRequestSchema = z.object({
|
export const ZAnalyzeRecipientsRequestSchema = z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user