feat: port quality, escalation, KB version, site-map KB, experiments and metrics
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
function stripHtml(value) {
|
||||
return String(value || '')
|
||||
.replace(/<br\s*\/?>/gi, '\n')
|
||||
.replace(/<[^>]+>/g, ' ')
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
// 把完整会话记录作为 Note 挂到商机(旧 bridge crm/chatLogger 的 LibreDesk 版)。
|
||||
async function attachChatToOpportunity({ client, twenty, convUuid, opportunityId, maxMessages = 100 }) {
|
||||
if (!client || !twenty || !convUuid || !opportunityId) return null;
|
||||
const messages = await client.getMessages(convUuid, maxMessages);
|
||||
const lines = (messages || [])
|
||||
.filter((m) => m && !m.private && (m.text_content || m.content))
|
||||
.sort((a, b) => Number(a.id) - Number(b.id))
|
||||
.map((m) => {
|
||||
const role = m.sender_type === 'contact' ? 'Customer' : 'Agent';
|
||||
return `[${role}] ${stripHtml(m.text_content || m.content).slice(0, 300)}`;
|
||||
})
|
||||
.filter((line) => line.trim().length > 12);
|
||||
if (!lines.length) return null;
|
||||
const text = lines.join('\n\n---\n\n').slice(0, 20000);
|
||||
const noteId = await twenty.createNote(text);
|
||||
if (noteId) await twenty.linkNoteToOpportunity(noteId, opportunityId);
|
||||
console.log(JSON.stringify({ ts: new Date().toISOString(), crm: 'chat_note', conversation: convUuid, opportunity: opportunityId, note_id: noteId }));
|
||||
return noteId;
|
||||
}
|
||||
|
||||
module.exports = { attachChatToOpportunity, stripHtml };
|
||||
Reference in New Issue
Block a user