Add Ask Mento, customer mood, and Pipecat speech-to-text.

Ship assistant answers, contact moods, voice dictation, and the related CRM UI so these can be deployed to production.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-03 14:20:55 +03:30
co-authored by Cursor
parent 0dd2966f3c
commit 7757c0837d
43 changed files with 5156 additions and 1741 deletions
@@ -1,6 +1,7 @@
import { BadRequestException, ConflictException, Injectable } from '@nestjs/common';
import ExcelJS from 'exceljs';
import type { ImportContactsResult } from '@mento/shared';
import type { ImportContactsResult, PersonMood } from '@mento/shared';
import { PERSON_MOOD_LABELS, PERSON_MOODS } from '@mento/shared';
import { PrismaService } from '../prisma/prisma.service';
import type { Actor } from '../common/record-scope';
import { ownerWhere } from '../common/record-scope';
@@ -21,6 +22,13 @@ function cellStr(value: ExcelJS.CellValue | undefined): string {
return String(value).trim();
}
function parseMood(raw?: string): PersonMood | undefined {
const value = raw?.trim();
if (!value) return undefined;
if (PERSON_MOODS.includes(value as PersonMood)) return value as PersonMood;
return PERSON_MOODS.find((mood) => PERSON_MOOD_LABELS[mood] === value);
}
function normalizeHeader(raw: string) {
return raw.trim().toLowerCase().replace(/\s+/g, '');
}
@@ -44,6 +52,10 @@ const PERSON_ALIASES: Record<string, string> = {
شرکت: 'companyName',
notes: 'notes',
یادداشت: 'notes',
mood: 'mood',
وضعیت: 'mood',
وضعیتمشتری: 'mood',
'وضعیت مشتری': 'mood',
};
const COMPANY_ALIASES: Record<string, string> = {
@@ -86,6 +98,7 @@ export class ContactsExcelService {
{ header: 'ایمیل', key: 'email', width: 28 },
{ header: 'سمت', key: 'position', width: 18 },
{ header: 'شرکت', key: 'companyName', width: 24 },
{ header: 'وضعیت مشتری', key: 'mood', width: 18 },
{ header: 'یادداشت', key: 'notes', width: 32 },
];
for (const p of items) {
@@ -97,6 +110,7 @@ export class ContactsExcelService {
email: p.email ?? '',
position: p.position ?? '',
companyName: p.company?.name ?? '',
mood: PERSON_MOOD_LABELS[p.mood || 'newcomer'],
notes: p.notes ?? '',
});
}
@@ -174,6 +188,7 @@ export class ContactsExcelService {
mobile: row.mobile || undefined,
position: row.position || undefined,
notes: row.notes || undefined,
mood: parseMood(row.mood),
companyId,
});
result.created += 1;