Emails: true markdown/Resend style — plain white, no card, clean type
TTS: prefix model with openai/ so LiteLLM routes correctly Email: horizontal rules instead of card border, spacious padding, wordmark + divider + body + divider + footer. Reads like a doc. TTS: tts-1 becomes openai/tts-1 automatically unless already prefixed.
This commit is contained in:
parent
ce8e959ea4
commit
535998f01a
2 changed files with 38 additions and 43 deletions
|
|
@ -38,78 +38,71 @@ function safeAppUrl() {
|
|||
}
|
||||
|
||||
// ============================================================
|
||||
// EMAIL TEMPLATES — clean, minimal (Linear / Resend style)
|
||||
// EMAIL TEMPLATES — markdown-style, Resend/Linear aesthetic
|
||||
// Plain, spacious, no decorative chrome. Reads like a document.
|
||||
// ============================================================
|
||||
function emailWrapper(body) {
|
||||
var siteName = process.env.SITE_NAME || 'Pediatric AI Scribe';
|
||||
var F = '-apple-system,BlinkMacSystemFont,\'Segoe UI\',Helvetica,Arial,sans-serif';
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>${escHtml(siteName)}</title>
|
||||
<style>
|
||||
body,table,td,p,a{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;}
|
||||
body,table,td,p,a{font-family:${F};}
|
||||
@media only screen and (max-width:600px){
|
||||
.wrap{width:100% !important;padding:0 16px !important;}
|
||||
.inner{padding:28px 24px !important;}
|
||||
.outer{padding:24px 16px !important;}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin:0;padding:0;background:#fafafa;-webkit-text-size-adjust:100%;">
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#fafafa;">
|
||||
<tr><td align="center" style="padding:40px 24px;">
|
||||
<body style="margin:0;padding:0;background:#ffffff;-webkit-text-size-adjust:100%;">
|
||||
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
|
||||
<tr><td class="outer" align="center" style="padding:48px 24px;">
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="max-width:520px;width:100%;">
|
||||
|
||||
<!-- Logo / wordmark -->
|
||||
<table role="presentation" class="wrap" cellpadding="0" cellspacing="0" border="0" style="max-width:520px;width:100%;margin-bottom:24px;">
|
||||
<tr><td>
|
||||
<p style="margin:0;font-size:15px;font-weight:600;color:#111827;letter-spacing:-0.2px;">${escHtml(siteName)}</p>
|
||||
</td></tr>
|
||||
</table>
|
||||
<!-- Wordmark -->
|
||||
<tr><td style="padding-bottom:32px;border-bottom:1px solid #e5e7eb;">
|
||||
<p style="margin:0;font-size:14px;font-weight:600;color:#111827;letter-spacing:-0.1px;">${escHtml(siteName)}</p>
|
||||
</td></tr>
|
||||
|
||||
<!-- Card -->
|
||||
<table role="presentation" class="wrap" cellpadding="0" cellspacing="0" border="0" style="max-width:520px;width:100%;background:#ffffff;border:1px solid #e5e7eb;border-radius:8px;">
|
||||
<tr><td class="inner" style="padding:36px 40px;">
|
||||
${body}
|
||||
</td></tr>
|
||||
</table>
|
||||
<!-- Body -->
|
||||
<tr><td style="padding:32px 0;">
|
||||
${body}
|
||||
</td></tr>
|
||||
|
||||
<!-- Footer -->
|
||||
<table role="presentation" class="wrap" cellpadding="0" cellspacing="0" border="0" style="max-width:520px;width:100%;margin-top:20px;">
|
||||
<tr><td>
|
||||
<p style="margin:0;font-size:12px;color:#9ca3af;line-height:1.6;">
|
||||
${escHtml(siteName)} · AI-powered clinical documentation<br>
|
||||
If you didn’t request this email, you can safely ignore it.
|
||||
</p>
|
||||
</td></tr>
|
||||
</table>
|
||||
<tr><td style="padding-top:24px;border-top:1px solid #e5e7eb;">
|
||||
<p style="margin:0;font-size:12px;color:#9ca3af;line-height:1.7;">
|
||||
${escHtml(siteName)} — AI-powered clinical documentation<br>
|
||||
If you didn’t request this, you can safely ignore it.
|
||||
</p>
|
||||
</td></tr>
|
||||
|
||||
</td></tr>
|
||||
</table>
|
||||
</table>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
function btnHtml(href, label) {
|
||||
return `<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:28px 0 4px;">
|
||||
<tr><td style="border-radius:6px;background:#111827;">
|
||||
return `<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="margin:24px 0;">
|
||||
<tr><td style="border-radius:5px;background:#111827;">
|
||||
<a href="${escHtml(href)}" target="_blank"
|
||||
style="display:inline-block;color:#ffffff;padding:12px 24px;border-radius:6px;
|
||||
text-decoration:none;font-weight:500;font-size:14px;
|
||||
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;
|
||||
letter-spacing:-0.1px;">${escHtml(label)}</a>
|
||||
style="display:inline-block;color:#ffffff;padding:11px 22px;border-radius:5px;
|
||||
text-decoration:none;font-weight:500;font-size:14px;line-height:1;
|
||||
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;">${escHtml(label)}</a>
|
||||
</td></tr>
|
||||
</table>`;
|
||||
}
|
||||
|
||||
function linkFallback(url) {
|
||||
return `<p style="margin:20px 0 6px;font-size:13px;color:#6b7280;">
|
||||
Or copy and paste this link into your browser:
|
||||
</p>
|
||||
<p style="margin:0;background:#f3f4f6;border-radius:4px;padding:10px 12px;
|
||||
font-size:12px;font-family:'SFMono-Regular',Consolas,monospace;
|
||||
word-break:break-all;color:#374151;line-height:1.5;">${escHtml(url)}</p>`;
|
||||
return `<p style="margin:16px 0 4px;font-size:13px;color:#6b7280;line-height:1.5;">If the button doesn’t work, copy this link:</p>
|
||||
<p style="margin:0;padding:10px 12px;background:#f9fafb;border:1px solid #e5e7eb;border-radius:4px;
|
||||
font-size:12px;font-family:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;
|
||||
word-break:break-all;color:#374151;line-height:1.6;">${escHtml(url)}</p>`;
|
||||
}
|
||||
|
||||
// Email helper — DB settings override env vars
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ router.post('/text-to-speech', authMiddleware, async (req, res) => {
|
|||
if (!process.env.LITELLM_API_BASE) return res.status(400).json({ error: 'LITELLM_API_BASE not set.' });
|
||||
// Use the full model path (e.g. vertex_ai/google-tts) or the model_name alias
|
||||
// from your LiteLLM model_list. Full path is safer if your config uses it directly.
|
||||
var ttsModel = process.env.LITELLM_TTS_MODEL || 'tts-1';
|
||||
// Prefix with openai/ so LiteLLM routes correctly to the TTS endpoint
|
||||
var rawModel = process.env.LITELLM_TTS_MODEL || 'tts-1';
|
||||
var ttsModel = rawModel.indexOf('/') === -1 ? 'openai/' + rawModel : rawModel;
|
||||
var ttsVoice = process.env.LITELLM_TTS_VOICE || 'en-US-Journey-F';
|
||||
var base = process.env.LITELLM_API_BASE.replace(/\/+$/, '');
|
||||
var ttsHeaders = { 'Content-Type': 'application/json' };
|
||||
|
|
|
|||
Loading…
Reference in a new issue