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:
@@ -32,17 +32,6 @@ export class AiService {
|
||||
noteType?: string;
|
||||
personName?: string | null;
|
||||
}): Promise<NoteAiExtract> {
|
||||
if (!this.isEnabled()) {
|
||||
throw new ServiceUnavailableException('هوش مصنوعی فعال نیست');
|
||||
}
|
||||
|
||||
const model = this.config.get<string>('AI_MODEL')?.trim() || 'gpt-4o-mini';
|
||||
const baseUrl =
|
||||
this.config.get<string>('AI_BASE_URL')?.trim() ||
|
||||
'https://api.openai.com/v1';
|
||||
const apiKey = this.config.get<string>('AI_API_KEY')!.trim();
|
||||
const timeoutMs = Number(this.config.get<string>('AI_TIMEOUT_MS') || 45000);
|
||||
|
||||
const system = `You analyze CRM notes in Persian/Farsi and extract structured data.
|
||||
Return ONLY valid JSON with this exact shape:
|
||||
{
|
||||
@@ -65,6 +54,25 @@ Rules:
|
||||
`Note:\n${input.body.trim()}`,
|
||||
].filter(Boolean);
|
||||
|
||||
const raw = await this.completeJson<Partial<NoteAiExtract>>(
|
||||
system,
|
||||
userParts.join('\n'),
|
||||
);
|
||||
return this.normalizeExtract(raw);
|
||||
}
|
||||
|
||||
async completeJson<T>(system: string, user: string): Promise<T> {
|
||||
if (!this.isEnabled()) {
|
||||
throw new ServiceUnavailableException('هوش مصنوعی فعال نیست');
|
||||
}
|
||||
|
||||
const model = this.config.get<string>('AI_MODEL')?.trim() || 'gpt-4o-mini';
|
||||
const baseUrl =
|
||||
this.config.get<string>('AI_BASE_URL')?.trim() ||
|
||||
'https://api.openai.com/v1';
|
||||
const apiKey = this.config.get<string>('AI_API_KEY')!.trim();
|
||||
const timeoutMs = Number(this.config.get<string>('AI_TIMEOUT_MS') || 45000);
|
||||
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
@@ -81,7 +89,7 @@ Rules:
|
||||
response_format: { type: 'json_object' },
|
||||
messages: [
|
||||
{ role: 'system', content: system },
|
||||
{ role: 'user', content: userParts.join('\n') },
|
||||
{ role: 'user', content: user },
|
||||
],
|
||||
}),
|
||||
signal: controller.signal,
|
||||
@@ -102,15 +110,18 @@ Rules:
|
||||
throw new BadRequestException('پاسخ مدل خالی بود');
|
||||
}
|
||||
|
||||
return this.normalizeExtract(JSON.parse(raw) as Partial<NoteAiExtract>);
|
||||
return JSON.parse(raw) as T;
|
||||
} catch (err) {
|
||||
if (err instanceof BadRequestException || err instanceof ServiceUnavailableException) {
|
||||
throw err;
|
||||
}
|
||||
if (err instanceof SyntaxError) {
|
||||
throw new BadRequestException('پاسخ مدل قابل خواندن نبود');
|
||||
}
|
||||
if (err instanceof Error && err.name === 'AbortError') {
|
||||
throw new ServiceUnavailableException('زمان پاسخ مدل هوش مصنوعی تمام شد');
|
||||
}
|
||||
throw new ServiceUnavailableException('تحلیل یادداشت با خطا مواجه شد');
|
||||
throw new ServiceUnavailableException('ارتباط با مدل هوش مصنوعی ناموفق بود');
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user