Seth commited on
Commit Β·
d2b0e4f
1
Parent(s): e72db37
update
Browse files
backend/app/gpt_service.py
CHANGED
|
@@ -428,9 +428,12 @@ def generate_linkedin_sequence(
|
|
| 428 |
plan_extra = "\nStrict mapping:\n"
|
| 429 |
for i, act in enumerate(li_actions, start=1):
|
| 430 |
if act == "linkedin_connect":
|
| 431 |
-
plan_extra +=
|
|
|
|
|
|
|
|
|
|
| 432 |
else:
|
| 433 |
-
plan_extra += f" Message {i}: LinkedIn DM / follow-up after connection (
|
| 434 |
plan_extra += (
|
| 435 |
"\nThe first LinkedIn touch in this list is always a connection request before any follow-up DMs.\n"
|
| 436 |
)
|
|
@@ -461,6 +464,7 @@ Contact Information:
|
|
| 461 |
|
| 462 |
Generate exactly {num_messages} messages (no more, no fewer) following the rules in the system prompt.
|
| 463 |
{plan_extra}
|
|
|
|
| 464 |
CRITICAL: Write for LinkedIn DMs or connection notes β short, plain, professional. No email-style subjects.
|
| 465 |
|
| 466 |
Output format (strict) β use exactly these {num_messages} labeled blocks and nothing beyond:
|
|
|
|
| 428 |
plan_extra = "\nStrict mapping:\n"
|
| 429 |
for i, act in enumerate(li_actions, start=1):
|
| 430 |
if act == "linkedin_connect":
|
| 431 |
+
plan_extra += (
|
| 432 |
+
f" Message {i}: LinkedIn CONNECTION REQUEST note only β under ~280 characters, "
|
| 433 |
+
"peer-to-peer and curious (no product pitch, no meeting ask, no vendor pressure).\n"
|
| 434 |
+
)
|
| 435 |
else:
|
| 436 |
+
plan_extra += f" Message {i}: LinkedIn DM / follow-up after connection (where you may add detail, context, and a soft next step).\n"
|
| 437 |
plan_extra += (
|
| 438 |
"\nThe first LinkedIn touch in this list is always a connection request before any follow-up DMs.\n"
|
| 439 |
)
|
|
|
|
| 464 |
|
| 465 |
Generate exactly {num_messages} messages (no more, no fewer) following the rules in the system prompt.
|
| 466 |
{plan_extra}
|
| 467 |
+
If the first message is a connection request: maximum ~280 characters, peer-to-peer curiosity only β no product name, no demo or meeting ask, no vendor pressure.
|
| 468 |
CRITICAL: Write for LinkedIn DMs or connection notes β short, plain, professional. No email-style subjects.
|
| 469 |
|
| 470 |
Output format (strict) β use exactly these {num_messages} labeled blocks and nothing beyond:
|
frontend/src/components/campaigns/CreateCampaignWizard.jsx
CHANGED
|
@@ -615,7 +615,7 @@ export default function CreateCampaignWizard({
|
|
| 615 |
if (!cur) {
|
| 616 |
cur =
|
| 617 |
LINKEDIN_DEFAULT_TEMPLATES[p.name] ||
|
| 618 |
-
`π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${p.name}. Sign with {{sender_name}}
|
| 619 |
}
|
| 620 |
if (!cur || cur.includes(WIZARD_SEQUENCE_TAG)) return;
|
| 621 |
next[p.name] = `${cur}\n\n${appendix}`;
|
|
|
|
| 615 |
if (!cur) {
|
| 616 |
cur =
|
| 617 |
LINKEDIN_DEFAULT_TEMPLATES[p.name] ||
|
| 618 |
+
`π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${p.name}. Message 1: peer-style connection only (~280 chars), no pitch; later messages add detail. Sign DMs with {{sender_name}}.\nMatch the Message count in the generation request exactly.`;
|
| 619 |
}
|
| 620 |
if (!cur || cur.includes(WIZARD_SEQUENCE_TAG)) return;
|
| 621 |
next[p.name] = `${cur}\n\n${appendix}`;
|
frontend/src/components/prompts/PromptEditor.jsx
CHANGED
|
@@ -686,62 +686,78 @@ Best,
|
|
| 686 |
export const LINKEDIN_DEFAULT_TEMPLATES = {
|
| 687 |
'Accounts Payable Automation': `π LINKEDIN SYSTEM PROMPT (DO NOT MODIFY)
|
| 688 |
|
| 689 |
-
You
|
| 690 |
|
| 691 |
π SENDER SIGN-OFF
|
| 692 |
|
| 693 |
-
|
| 694 |
{{sender_name}}
|
| 695 |
-
Never use the prospect as the sender.
|
| 696 |
-
|
| 697 |
-
π GOAL
|
| 698 |
-
|
| 699 |
-
Earn a short reply or accept that leads to a 15β20 minute working conversation about AP invoice throughput, approvals, and month-end close β not generic "trends" chat.
|
| 700 |
|
| 701 |
π NO FAKE PERSONALIZATION
|
| 702 |
|
| 703 |
-
No "I saw your post", no invented news.
|
| 704 |
|
| 705 |
-
π MESSAGE 1 β CONNECTION REQUEST NOTE
|
| 706 |
|
| 707 |
-
|
| 708 |
-
β’ One line tied to their role or industry (from inputs).
|
| 709 |
-
β’ One concise question or reason to accept.
|
| 710 |
-
β’ No buzzwords; no emojis; no "I'd love to pick your brain" fluff.
|
| 711 |
|
| 712 |
-
|
| 713 |
-
|
| 714 |
-
β’
|
| 715 |
-
β’
|
|
|
|
|
|
|
| 716 |
|
| 717 |
-
π
|
| 718 |
|
| 719 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 720 |
|
| 721 |
π OUTPUT
|
| 722 |
|
| 723 |
-
Use exactly
|
| 724 |
|
| 725 |
'Sales Order Processing': `π LINKEDIN SYSTEM PROMPT
|
| 726 |
-
You write
|
| 727 |
-
|
| 728 |
-
|
|
|
|
|
|
|
|
|
|
| 729 |
Match the exact Message 1β¦N count from the campaign user prompt.`,
|
| 730 |
|
| 731 |
'Document Management': `π LINKEDIN SYSTEM PROMPT
|
| 732 |
-
LinkedIn
|
| 733 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 734 |
|
| 735 |
'Invoice Processing': `π LINKEDIN SYSTEM PROMPT
|
| 736 |
-
|
|
|
|
|
|
|
|
|
|
| 737 |
Follow the user prompt's Message count exactly.`,
|
| 738 |
|
| 739 |
'Expense Management': `π LINKEDIN SYSTEM PROMPT
|
| 740 |
-
|
|
|
|
|
|
|
|
|
|
| 741 |
Write exactly as many labeled Message sections as the user prompt specifies.`,
|
| 742 |
|
| 743 |
'Procurement Automation': `π LINKEDIN SYSTEM PROMPT
|
| 744 |
-
|
|
|
|
|
|
|
|
|
|
| 745 |
Use only the Message 1β¦N blocks requested in the user prompt; same count as the campaign sequence.`,
|
| 746 |
};
|
| 747 |
|
|
@@ -780,7 +796,7 @@ const PromptEditor = forwardRef(function PromptEditor(
|
|
| 780 |
const emailDefault = DEFAULT_TEMPLATES[product.name];
|
| 781 |
const liDefault = LINKEDIN_DEFAULT_TEMPLATES[product.name];
|
| 782 |
const emailFallback = `Subject: {{first_name}}, let's talk about ${product.name}\n\nHi {{first_name}},\n\nI wanted to reach out about how ${product.name} could benefit {{company}}.\n\n[Your personalized message here]\n\nBest,\n{{sender_name}}`;
|
| 783 |
-
const liFallback = `π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${product.name}.
|
| 784 |
const email = savedEmail || emailDefault || emailFallback;
|
| 785 |
if (includeLinkedinInCampaign) {
|
| 786 |
const li = savedLi || liDefault || liFallback;
|
|
@@ -803,7 +819,7 @@ const PromptEditor = forwardRef(function PromptEditor(
|
|
| 803 |
} else if (defaultTemplate) {
|
| 804 |
newPrompts[product.name] = defaultTemplate;
|
| 805 |
} else if (variant === 'linkedin') {
|
| 806 |
-
newPrompts[product.name] = `π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${product.name}.
|
| 807 |
} else {
|
| 808 |
newPrompts[product.name] = `Subject: {{first_name}}, let's talk about ${product.name}\n\nHi {{first_name}},\n\nI wanted to reach out about how ${product.name} could benefit {{company}}.\n\n[Your personalized message here]\n\nBest,\n{{sender_name}}`;
|
| 809 |
}
|
|
@@ -874,7 +890,7 @@ const PromptEditor = forwardRef(function PromptEditor(
|
|
| 874 |
if (includeLinkedinInCampaign) {
|
| 875 |
const liDefault =
|
| 876 |
LINKEDIN_DEFAULT_TEMPLATES[productName] ||
|
| 877 |
-
`π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${productName}. Sign with {{sender_name}}
|
| 878 |
handlePromptChange(
|
| 879 |
productName,
|
| 880 |
`${emailDefault}${CAMPAIGN_COMBINED_PROMPT_SPLIT}${liDefault}`
|
|
@@ -888,7 +904,7 @@ const PromptEditor = forwardRef(function PromptEditor(
|
|
| 888 |
const defaultTemplate =
|
| 889 |
library[productName] ||
|
| 890 |
(variant === 'linkedin'
|
| 891 |
-
? `π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${productName}. Sign with {{sender_name}}
|
| 892 |
: `Subject: {{first_name}}, let's talk about ${productName}\n\nHi {{first_name}},\n\nI wanted to reach out about how ${productName} could benefit {{company}}.\n\n[Your personalized message here]\n\nBest,\n{{sender_name}}`);
|
| 893 |
handlePromptChange(productName, defaultTemplate);
|
| 894 |
};
|
|
|
|
| 686 |
export const LINKEDIN_DEFAULT_TEMPLATES = {
|
| 687 |
'Accounts Payable Automation': `π LINKEDIN SYSTEM PROMPT (DO NOT MODIFY)
|
| 688 |
|
| 689 |
+
You write LinkedIn connection notes and follow-up DMs for AP / finance leaders (mid-market North America). Tone: peer curiosity first, substance after they accept β like a leader reaching out to compare notes, not a vendor opening with a pitch.
|
| 690 |
|
| 691 |
π SENDER SIGN-OFF
|
| 692 |
|
| 693 |
+
In DMs, you may close with the token on its own line (app substitutes the LinkedIn display name from Settings):
|
| 694 |
{{sender_name}}
|
| 695 |
+
Never use the prospect as the sender. For Message 1 (connection note), a sign-off is optional if space is tight; if you include one, use only {{sender_name}} on its own short line.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 696 |
|
| 697 |
π NO FAKE PERSONALIZATION
|
| 698 |
|
| 699 |
+
No "I saw your post", no invented awards or news. Hyper-personalize only from: first name, title, company, industry, location, employee count when provided.
|
| 700 |
|
| 701 |
+
π MESSAGE 1 β CONNECTION REQUEST NOTE ONLY (~280 characters max including spaces)
|
| 702 |
|
| 703 |
+
Purpose: open the door. Sound human and low-pressure.
|
|
|
|
|
|
|
|
|
|
| 704 |
|
| 705 |
+
Rules:
|
| 706 |
+
β’ Do NOT name EZOFIS or any product. Do NOT propose a call, demo, or meeting. Do NOT ask them to evaluate a solution.
|
| 707 |
+
β’ Do NOT use sales openers ("quick question", "picking your brain", "15 minutes", "ROI").
|
| 708 |
+
β’ DO weave in one specific nod to their world (role + company or industry) so it feels one-to-one.
|
| 709 |
+
β’ Style examples to emulate (rewrite in your own words each time): exploring how finance / operations leaders are approaching digitization and practical automation; would value connecting and exchanging perspectives; or a genuine note about synergy / learning from peers in their space.
|
| 710 |
+
β’ 2β4 short sentences max; calm; no emojis; no em dashes.
|
| 711 |
|
| 712 |
+
π MESSAGE 2+ β FOLLOW-UP DMs (this is where detail belongs)
|
| 713 |
|
| 714 |
+
β’ First DM after connect: Briefly reference that you just connected. Then share credible context: how you work with organizations on finance / AP-side automation from planning through execution; lean approach, practical use cases, visible outcomes (fewer stuck invoices, clearer approvals, less manual chase) β tie to their industry or company type from inputs.
|
| 715 |
+
β’ Mention EZOFIS AP Automation by name only here (and in later DMs if needed), in plain language β not a feature dump.
|
| 716 |
+
β’ One soft, no-obligation line about a conversation if useful (e.g. "happy to compare notes if your team is looking at this").
|
| 717 |
+
β’ Later DMs: add one new layer each time (e.g. month-end, exceptions, 3-way match, audit trail) + optional line about how you typically start (consultation / understanding workflow / prototype "to-be" β describe generically, no fake claims about their process).
|
| 718 |
+
β’ Each DM: 2β5 short paragraphs; end with one easy question or gentle opt-in β never pushy.
|
| 719 |
|
| 720 |
π OUTPUT
|
| 721 |
|
| 722 |
+
Use exactly Message 1 β¦ Message N from the user prompt. No extra messages.`,
|
| 723 |
|
| 724 |
'Sales Order Processing': `π LINKEDIN SYSTEM PROMPT
|
| 725 |
+
You write connection notes and DMs for order-to-cash / AR operations leaders. Sign DMs with {{sender_name}} on its own line when signing off (app substitutes LinkedIn display name). Never use the prospect as sender.
|
| 726 |
+
|
| 727 |
+
Message 1 (connection, ~280 chars): peer opener only β how leaders approach order documentation, delivery proof, or operational digitization at their scale. Hyper-personalize with title, company, industry from inputs. No product name, no meeting ask, no pitch.
|
| 728 |
+
|
| 729 |
+
Message 2+: Reference the connection; then EZOFIS AR & Order Automation and practical detail (POs, pick slips, field capture, fewer stalled orders). Calm, structured paragraphs like a follow-up note to a peer; soft optional conversation. One question per DM.
|
| 730 |
+
|
| 731 |
Match the exact Message 1β¦N count from the campaign user prompt.`,
|
| 732 |
|
| 733 |
'Document Management': `π LINKEDIN SYSTEM PROMPT
|
| 734 |
+
LinkedIn for document / records leaders. {{sender_name}} on its own line when you sign a DM.
|
| 735 |
+
|
| 736 |
+
Message 1 (~280 chars): light, peer-style reason to connect β how teams handle documents, versions, or audit readiness in their industry; personalize with company/role/industry from inputs only. No product pitch or meeting ask.
|
| 737 |
+
|
| 738 |
+
Message 2+: EZOFIS DMS relevance, capture/classification/search in plain language, more detail and optional no-obligation chat. One question per DM.
|
| 739 |
+
|
| 740 |
+
Match Message count from the user prompt.`,
|
| 741 |
|
| 742 |
'Invoice Processing': `π LINKEDIN SYSTEM PROMPT
|
| 743 |
+
Message 1: connection note ~280 characters β curious peer tone, personalized with {{first_name}}, company, industry from inputs; no product name, no demo/call ask.
|
| 744 |
+
|
| 745 |
+
Message 2+: invoice / AP automation context, EZOFIS where appropriate, structured follow-ups (similar rhythm to a multi-paragraph DM you would send after someone accepts). Sign with {{sender_name}} when closing DMs.
|
| 746 |
+
|
| 747 |
Follow the user prompt's Message count exactly.`,
|
| 748 |
|
| 749 |
'Expense Management': `π LINKEDIN SYSTEM PROMPT
|
| 750 |
+
Message 1 (~280 chars): connect as a peer exploring how finance teams handle expense workflows and visibility β personalize with role/company/industry from inputs. No product pitch in the connection note.
|
| 751 |
+
|
| 752 |
+
Message 2+: expense operations and your solution area with substance; sign DMs with {{sender_name}}. Professional, no buzzwords.
|
| 753 |
+
|
| 754 |
Write exactly as many labeled Message sections as the user prompt specifies.`,
|
| 755 |
|
| 756 |
'Procurement Automation': `π LINKEDIN SYSTEM PROMPT
|
| 757 |
+
Message 1 (~280 chars): light opener to procurement / sourcing leaders β growth, supplier coordination, or how peers approach digitization; hyper-personalize from inputs. No vendor pitch or meeting ask in the note.
|
| 758 |
+
|
| 759 |
+
Message 2+: practical procurement automation angles, soft opt-in to talk, {{sender_name}} on DM sign-offs.
|
| 760 |
+
|
| 761 |
Use only the Message 1β¦N blocks requested in the user prompt; same count as the campaign sequence.`,
|
| 762 |
};
|
| 763 |
|
|
|
|
| 796 |
const emailDefault = DEFAULT_TEMPLATES[product.name];
|
| 797 |
const liDefault = LINKEDIN_DEFAULT_TEMPLATES[product.name];
|
| 798 |
const emailFallback = `Subject: {{first_name}}, let's talk about ${product.name}\n\nHi {{first_name}},\n\nI wanted to reach out about how ${product.name} could benefit {{company}}.\n\n[Your personalized message here]\n\nBest,\n{{sender_name}}`;
|
| 799 |
+
const liFallback = `π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${product.name}. Message 1: short peer-style connection note only (~280 chars), no product pitch or meeting ask β hyper-personalize from inputs. Later messages: add detail and relevance; sign DMs with {{sender_name}} on its own line.\nFollow the exact number of labeled Message blocks in the generation request (Message 1 β¦ Message N). Do not add extra messages.`;
|
| 800 |
const email = savedEmail || emailDefault || emailFallback;
|
| 801 |
if (includeLinkedinInCampaign) {
|
| 802 |
const li = savedLi || liDefault || liFallback;
|
|
|
|
| 819 |
} else if (defaultTemplate) {
|
| 820 |
newPrompts[product.name] = defaultTemplate;
|
| 821 |
} else if (variant === 'linkedin') {
|
| 822 |
+
newPrompts[product.name] = `π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${product.name}. Message 1: ~280 character peer opener only β no pitch or meeting ask; personalize with {{first_name}}, {{company}} from inputs. Later messages: detail and soft next step; sign DMs with {{sender_name}}.\nUse the exact Message 1β¦N count from the generation request; do not invent extra touches.`;
|
| 823 |
} else {
|
| 824 |
newPrompts[product.name] = `Subject: {{first_name}}, let's talk about ${product.name}\n\nHi {{first_name}},\n\nI wanted to reach out about how ${product.name} could benefit {{company}}.\n\n[Your personalized message here]\n\nBest,\n{{sender_name}}`;
|
| 825 |
}
|
|
|
|
| 890 |
if (includeLinkedinInCampaign) {
|
| 891 |
const liDefault =
|
| 892 |
LINKEDIN_DEFAULT_TEMPLATES[productName] ||
|
| 893 |
+
`π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${productName}. Message 1: short peer connection note only, no pitch; later messages carry detail. Sign DMs with {{sender_name}}.\nMatch the Message count in the generation request exactly.`;
|
| 894 |
handlePromptChange(
|
| 895 |
productName,
|
| 896 |
`${emailDefault}${CAMPAIGN_COMBINED_PROMPT_SPLIT}${liDefault}`
|
|
|
|
| 904 |
const defaultTemplate =
|
| 905 |
library[productName] ||
|
| 906 |
(variant === 'linkedin'
|
| 907 |
+
? `π LINKEDIN SYSTEM PROMPT\n\nYou write LinkedIn connection notes and DMs for ${productName}. Message 1: peer opener only (~280 chars), no product or meeting ask; later messages add substance. Sign DMs with {{sender_name}}.\nMatch the Message count in the generation request exactly.`
|
| 908 |
: `Subject: {{first_name}}, let's talk about ${productName}\n\nHi {{first_name}},\n\nI wanted to reach out about how ${productName} could benefit {{company}}.\n\n[Your personalized message here]\n\nBest,\n{{sender_name}}`);
|
| 909 |
handlePromptChange(productName, defaultTemplate);
|
| 910 |
};
|