@contenify/chatbot 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -48
- package/dist/index.js +527 -354
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +533 -360
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +110 -12
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -167,7 +167,7 @@ var savePreferencesApi = async ({
|
|
|
167
167
|
import { jsx } from "react/jsx-runtime";
|
|
168
168
|
var defaultPreferences = {
|
|
169
169
|
chatbot: {
|
|
170
|
-
name: "
|
|
170
|
+
name: "ContenifyAI Assistant",
|
|
171
171
|
primaryColor: "#10b981",
|
|
172
172
|
secondaryColor: "#064e3b",
|
|
173
173
|
theme: "system"
|
|
@@ -266,42 +266,83 @@ function usePreferences() {
|
|
|
266
266
|
// components/chatbot/ChatBot.tsx
|
|
267
267
|
import { useState as useState7 } from "react";
|
|
268
268
|
|
|
269
|
-
//
|
|
270
|
-
function
|
|
271
|
-
if (!raw)
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
269
|
+
// src/utils/ aiJsonParser.ts
|
|
270
|
+
function extractJSON(raw) {
|
|
271
|
+
if (!raw) return null;
|
|
272
|
+
let cleaned = raw.replace(/```json/gi, "").replace(/```/g, "").trim();
|
|
273
|
+
const first = cleaned.indexOf("{");
|
|
274
|
+
const last = cleaned.lastIndexOf("}");
|
|
275
|
+
if (first === -1 || last === -1 || last <= first) return null;
|
|
276
|
+
const possibleJson = cleaned.substring(first, last + 1);
|
|
277
|
+
try {
|
|
278
|
+
return JSON.parse(possibleJson);
|
|
279
|
+
} catch (err) {
|
|
280
|
+
console.warn("JSON parse failed:", err);
|
|
281
|
+
return null;
|
|
279
282
|
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/utils/decodeUnicode.ts
|
|
286
|
+
function decodeUnicode(text) {
|
|
287
|
+
if (!text) return "";
|
|
280
288
|
try {
|
|
281
|
-
|
|
282
|
-
return {
|
|
283
|
-
title: parsed.title || "",
|
|
284
|
-
article: parsed.article || parsed.content || "",
|
|
285
|
-
metaKeywords: Array.isArray(parsed.metaKeywords) ? parsed.metaKeywords : []
|
|
286
|
-
};
|
|
289
|
+
return JSON.parse(`"${text.replace(/"/g, '\\"')}"`);
|
|
287
290
|
} catch (e) {
|
|
288
|
-
|
|
291
|
+
return text;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/utils/articleTextToHtml.ts
|
|
296
|
+
function articleTextToHtml(text) {
|
|
297
|
+
if (!text) return "";
|
|
298
|
+
text = text.replace(/\\n/g, "\n");
|
|
299
|
+
const lines = text.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
300
|
+
let html = "";
|
|
301
|
+
for (const line of lines) {
|
|
302
|
+
if (line.length < 80 && !line.endsWith("\u0964") && !line.endsWith(".")) {
|
|
303
|
+
html += `<h2>${line}</h2>`;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
html += `<p>${line}</p>`;
|
|
307
|
+
}
|
|
308
|
+
return html;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/utils/formatAIContent.ts
|
|
312
|
+
function formatAIContent(raw) {
|
|
313
|
+
const empty = {
|
|
314
|
+
isArticle: false,
|
|
315
|
+
title: "",
|
|
316
|
+
subtitle: "",
|
|
317
|
+
articleHtml: "",
|
|
318
|
+
article: "",
|
|
319
|
+
metaDescription: "",
|
|
320
|
+
metaKeywords: [],
|
|
321
|
+
plainText: ""
|
|
322
|
+
};
|
|
323
|
+
if (!raw) return empty;
|
|
324
|
+
const parsed = extractJSON(raw);
|
|
325
|
+
if (parsed && (parsed.title || parsed.article)) {
|
|
326
|
+
const rawArticle = (parsed.article || "").trim();
|
|
327
|
+
const safeArticle = decodeUnicode(rawArticle);
|
|
328
|
+
const isHtml = /<[a-z][\s\S]*>/i.test(safeArticle);
|
|
329
|
+
const articleHtml = isHtml ? safeArticle : articleTextToHtml(safeArticle);
|
|
289
330
|
return {
|
|
290
|
-
|
|
291
|
-
|
|
331
|
+
isArticle: true,
|
|
332
|
+
title: parsed.title || "",
|
|
333
|
+
subtitle: parsed.subtitle || "",
|
|
334
|
+
articleHtml,
|
|
335
|
+
article: rawArticle,
|
|
336
|
+
metaDescription: parsed.metaDescription || "",
|
|
337
|
+
metaKeywords: Array.isArray(parsed.metaKeywords) ? parsed.metaKeywords : [],
|
|
338
|
+
plainText: raw
|
|
292
339
|
};
|
|
293
340
|
}
|
|
341
|
+
return __spreadProps(__spreadValues({}, empty), { plainText: raw });
|
|
294
342
|
}
|
|
295
|
-
var hexToRgba = (hex, opacity) => {
|
|
296
|
-
const sanitizedHex = hex.replace("#", "");
|
|
297
|
-
const r = parseInt(sanitizedHex.substring(0, 2), 16);
|
|
298
|
-
const g = parseInt(sanitizedHex.substring(2, 4), 16);
|
|
299
|
-
const b = parseInt(sanitizedHex.substring(4, 6), 16);
|
|
300
|
-
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
301
|
-
};
|
|
302
343
|
|
|
303
344
|
// components/chatbot/ChatWindow.tsx
|
|
304
|
-
import { Check, Copy, Edit3, Send, SendHorizontal, Zap, X as X2, RefreshCcw as RefreshCcw2, FileText, ListChecks, Share2, BookOpen, Mail, Key } from "lucide-react";
|
|
345
|
+
import { Check, Copy, Edit3, Send, SendHorizontal, Zap, X as X2, RefreshCcw as RefreshCcw2, FileText, ListChecks, Share2, BookOpen, Mail, Key, Loader2 } from "lucide-react";
|
|
305
346
|
import { useLayoutEffect, useRef, useState as useState4, useEffect as useEffect4 } from "react";
|
|
306
347
|
|
|
307
348
|
// components/chatbot/EditModal.tsx
|
|
@@ -490,38 +531,38 @@ function useTheme() {
|
|
|
490
531
|
|
|
491
532
|
// components/chatbot/EditModal.tsx
|
|
492
533
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
534
|
+
function toSlug(text) {
|
|
535
|
+
return text.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
|
|
536
|
+
}
|
|
493
537
|
function EditModal({
|
|
494
538
|
isOpen,
|
|
539
|
+
initialTitle = "",
|
|
540
|
+
initialSubtitle = "",
|
|
495
541
|
initialContent,
|
|
542
|
+
initialMetaDescription = "",
|
|
496
543
|
metaKeywords,
|
|
497
544
|
onClose,
|
|
498
545
|
onSaveDraft,
|
|
499
546
|
onPost
|
|
500
547
|
}) {
|
|
501
548
|
const { primaryColor } = useTheme();
|
|
549
|
+
const [title, setTitle] = useState2("");
|
|
550
|
+
const [subtitle, setSubtitle] = useState2("");
|
|
551
|
+
const [slug, setSlug] = useState2("");
|
|
552
|
+
const [slugEdited, setSlugEdited] = useState2(false);
|
|
553
|
+
const [metaDescription, setMetaDescription] = useState2("");
|
|
502
554
|
const [content, setContent] = useState2("");
|
|
503
555
|
const [keywords, setKeywords] = useState2(metaKeywords);
|
|
504
556
|
const [newKeyword, setNewKeyword] = useState2("");
|
|
505
|
-
const markdownToHtml = (text) => {
|
|
506
|
-
const lines = text.split("\n").filter((line) => line.trim());
|
|
507
|
-
let html = "";
|
|
508
|
-
lines.forEach((line) => {
|
|
509
|
-
const trimmed = line.trim();
|
|
510
|
-
if (trimmed.startsWith("# ")) {
|
|
511
|
-
html += `<h1>${trimmed.replace(/^#\s+/, "")}</h1>`;
|
|
512
|
-
} else if (trimmed.startsWith("## ")) {
|
|
513
|
-
html += `<h2>${trimmed.replace(/^##\s+/, "")}</h2>`;
|
|
514
|
-
} else {
|
|
515
|
-
html += `<p>${trimmed}</p>`;
|
|
516
|
-
}
|
|
517
|
-
});
|
|
518
|
-
return html;
|
|
519
|
-
};
|
|
520
557
|
useEffect3(() => {
|
|
521
|
-
|
|
522
|
-
|
|
558
|
+
setTitle(initialTitle);
|
|
559
|
+
setSubtitle(initialSubtitle);
|
|
560
|
+
setMetaDescription(initialMetaDescription);
|
|
561
|
+
setSlug(toSlug(initialTitle));
|
|
562
|
+
setSlugEdited(false);
|
|
563
|
+
setContent(initialContent);
|
|
523
564
|
setKeywords(metaKeywords);
|
|
524
|
-
}, [initialContent, metaKeywords]);
|
|
565
|
+
}, [initialTitle, initialSubtitle, initialContent, initialMetaDescription, metaKeywords]);
|
|
525
566
|
useEffect3(() => {
|
|
526
567
|
if (isOpen) {
|
|
527
568
|
document.body.style.overflow = "hidden";
|
|
@@ -532,6 +573,16 @@ function EditModal({
|
|
|
532
573
|
document.body.style.overflow = "";
|
|
533
574
|
};
|
|
534
575
|
}, [isOpen]);
|
|
576
|
+
const handleTitleChange = (value) => {
|
|
577
|
+
setTitle(value);
|
|
578
|
+
if (!slugEdited) {
|
|
579
|
+
setSlug(toSlug(value));
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
const handleSlugChange = (value) => {
|
|
583
|
+
setSlug(toSlug(value));
|
|
584
|
+
setSlugEdited(true);
|
|
585
|
+
};
|
|
535
586
|
const handleAddKeyword = () => {
|
|
536
587
|
if (newKeyword.trim() && !keywords.includes(newKeyword.trim())) {
|
|
537
588
|
setKeywords([...keywords, newKeyword.trim()]);
|
|
@@ -547,28 +598,62 @@ function EditModal({
|
|
|
547
598
|
handleAddKeyword();
|
|
548
599
|
}
|
|
549
600
|
};
|
|
601
|
+
const getEditData = () => ({
|
|
602
|
+
title,
|
|
603
|
+
subtitle,
|
|
604
|
+
article: content,
|
|
605
|
+
metaDescription,
|
|
606
|
+
slug,
|
|
607
|
+
keywords
|
|
608
|
+
});
|
|
550
609
|
if (!isOpen) return null;
|
|
551
610
|
return /* @__PURE__ */ jsxs2("div", { className: "cnfy-edit-modal-overlay", children: [
|
|
552
|
-
/* @__PURE__ */ jsx3(
|
|
553
|
-
"div",
|
|
554
|
-
{
|
|
555
|
-
className: "cnfy-edit-modal-backdrop",
|
|
556
|
-
onClick: onClose
|
|
557
|
-
}
|
|
558
|
-
),
|
|
611
|
+
/* @__PURE__ */ jsx3("div", { className: "cnfy-edit-modal-backdrop", onClick: onClose }),
|
|
559
612
|
/* @__PURE__ */ jsxs2("div", { className: "cnfy-edit-modal", children: [
|
|
560
613
|
/* @__PURE__ */ jsxs2("div", { className: "cnfy-edit-modal-header", children: [
|
|
561
614
|
/* @__PURE__ */ jsx3("h2", { className: "cnfy-edit-modal-title", children: "Edit Article" }),
|
|
562
|
-
/* @__PURE__ */ jsx3(
|
|
563
|
-
"button",
|
|
564
|
-
{
|
|
565
|
-
onClick: onClose,
|
|
566
|
-
className: "cnfy-edit-modal-close-btn",
|
|
567
|
-
children: /* @__PURE__ */ jsx3(X, { size: 20, className: "cnfy-edit-modal-close-icon" })
|
|
568
|
-
}
|
|
569
|
-
)
|
|
615
|
+
/* @__PURE__ */ jsx3("button", { onClick: onClose, className: "cnfy-edit-modal-close-btn", children: /* @__PURE__ */ jsx3(X, { size: 20, className: "cnfy-edit-modal-close-icon" }) })
|
|
570
616
|
] }),
|
|
571
617
|
/* @__PURE__ */ jsxs2("div", { className: "cnfy-edit-modal-body", children: [
|
|
618
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
619
|
+
/* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Title" }),
|
|
620
|
+
/* @__PURE__ */ jsx3(
|
|
621
|
+
"input",
|
|
622
|
+
{
|
|
623
|
+
type: "text",
|
|
624
|
+
value: title,
|
|
625
|
+
onChange: (e) => handleTitleChange(e.target.value),
|
|
626
|
+
placeholder: "Article title...",
|
|
627
|
+
className: "cnfy-edit-input"
|
|
628
|
+
}
|
|
629
|
+
)
|
|
630
|
+
] }),
|
|
631
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
632
|
+
/* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Subtitle" }),
|
|
633
|
+
/* @__PURE__ */ jsx3(
|
|
634
|
+
"input",
|
|
635
|
+
{
|
|
636
|
+
type: "text",
|
|
637
|
+
value: subtitle,
|
|
638
|
+
onChange: (e) => setSubtitle(e.target.value),
|
|
639
|
+
placeholder: "Article subtitle...",
|
|
640
|
+
className: "cnfy-edit-input"
|
|
641
|
+
}
|
|
642
|
+
)
|
|
643
|
+
] }),
|
|
644
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
645
|
+
/* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Slug" }),
|
|
646
|
+
/* @__PURE__ */ jsx3(
|
|
647
|
+
"input",
|
|
648
|
+
{
|
|
649
|
+
type: "text",
|
|
650
|
+
value: slug,
|
|
651
|
+
onChange: (e) => handleSlugChange(e.target.value),
|
|
652
|
+
placeholder: "article-url-slug",
|
|
653
|
+
className: "cnfy-edit-input cnfy-edit-input--mono"
|
|
654
|
+
}
|
|
655
|
+
)
|
|
656
|
+
] }),
|
|
572
657
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
573
658
|
/* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Article Content" }),
|
|
574
659
|
/* @__PURE__ */ jsx3(
|
|
@@ -581,26 +666,32 @@ function EditModal({
|
|
|
581
666
|
)
|
|
582
667
|
] }),
|
|
583
668
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
584
|
-
/* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Meta
|
|
585
|
-
/* @__PURE__ */ jsx3(
|
|
586
|
-
"
|
|
669
|
+
/* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Meta Description" }),
|
|
670
|
+
/* @__PURE__ */ jsx3(
|
|
671
|
+
"textarea",
|
|
587
672
|
{
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
673
|
+
value: metaDescription,
|
|
674
|
+
onChange: (e) => setMetaDescription(e.target.value),
|
|
675
|
+
placeholder: "Brief description for search engines...",
|
|
676
|
+
className: "cnfy-edit-textarea",
|
|
677
|
+
rows: 3
|
|
678
|
+
}
|
|
679
|
+
)
|
|
680
|
+
] }),
|
|
681
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
682
|
+
/* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Meta Keywords" }),
|
|
683
|
+
/* @__PURE__ */ jsx3("div", { className: "cnfy-keyword-list", children: keywords.map((keyword, index) => /* @__PURE__ */ jsxs2("span", { className: "cnfy-keyword-tag", children: [
|
|
684
|
+
"#",
|
|
685
|
+
keyword,
|
|
686
|
+
/* @__PURE__ */ jsx3(
|
|
687
|
+
"button",
|
|
688
|
+
{
|
|
689
|
+
onClick: () => handleRemoveKeyword(index),
|
|
690
|
+
className: "cnfy-keyword-remove-btn",
|
|
691
|
+
children: /* @__PURE__ */ jsx3(X, { size: 14 })
|
|
692
|
+
}
|
|
693
|
+
)
|
|
694
|
+
] }, index)) }),
|
|
604
695
|
/* @__PURE__ */ jsxs2("div", { className: "cnfy-keyword-input-row", children: [
|
|
605
696
|
/* @__PURE__ */ jsx3(
|
|
606
697
|
"input",
|
|
@@ -613,30 +704,16 @@ function EditModal({
|
|
|
613
704
|
className: "cnfy-keyword-input"
|
|
614
705
|
}
|
|
615
706
|
),
|
|
616
|
-
/* @__PURE__ */ jsx3(
|
|
617
|
-
"button",
|
|
618
|
-
{
|
|
619
|
-
onClick: handleAddKeyword,
|
|
620
|
-
className: "cnfy-btn-add-keyword",
|
|
621
|
-
children: "Add"
|
|
622
|
-
}
|
|
623
|
-
)
|
|
707
|
+
/* @__PURE__ */ jsx3("button", { onClick: handleAddKeyword, className: "cnfy-btn-add-keyword", children: "Add" })
|
|
624
708
|
] })
|
|
625
709
|
] })
|
|
626
710
|
] }),
|
|
627
711
|
/* @__PURE__ */ jsxs2("div", { className: "cnfy-edit-modal-footer", children: [
|
|
712
|
+
/* @__PURE__ */ jsx3("button", { onClick: onClose, className: "cnfy-btn-footer-cancel", children: "Cancel" }),
|
|
628
713
|
/* @__PURE__ */ jsx3(
|
|
629
714
|
"button",
|
|
630
715
|
{
|
|
631
|
-
onClick:
|
|
632
|
-
className: "cnfy-btn-footer-cancel",
|
|
633
|
-
children: "Cancel"
|
|
634
|
-
}
|
|
635
|
-
),
|
|
636
|
-
/* @__PURE__ */ jsx3(
|
|
637
|
-
"button",
|
|
638
|
-
{
|
|
639
|
-
onClick: () => onSaveDraft(content, keywords),
|
|
716
|
+
onClick: () => onSaveDraft(getEditData()),
|
|
640
717
|
className: "cnfy-btn-save-draft",
|
|
641
718
|
children: "Save Draft"
|
|
642
719
|
}
|
|
@@ -644,7 +721,7 @@ function EditModal({
|
|
|
644
721
|
/* @__PURE__ */ jsx3(
|
|
645
722
|
"button",
|
|
646
723
|
{
|
|
647
|
-
onClick: () => onPost(
|
|
724
|
+
onClick: () => onPost(getEditData()),
|
|
648
725
|
className: "cnfy-btn-post-article",
|
|
649
726
|
style: { backgroundColor: primaryColor, color: "#fff" },
|
|
650
727
|
children: "Post"
|
|
@@ -844,7 +921,7 @@ var getNewsBySource = async (sourceId) => {
|
|
|
844
921
|
|
|
845
922
|
// components/chatbot/ChatWindow.tsx
|
|
846
923
|
import Select from "react-select";
|
|
847
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
924
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
848
925
|
var ACTION_ICONS = {
|
|
849
926
|
recreate_article: RefreshCcw2,
|
|
850
927
|
create_summary: ListChecks,
|
|
@@ -858,12 +935,13 @@ function ChatWindow({
|
|
|
858
935
|
onSend,
|
|
859
936
|
onSelectNews,
|
|
860
937
|
isStreaming = false,
|
|
938
|
+
activeField,
|
|
861
939
|
analyzedData,
|
|
862
940
|
onSelectAction,
|
|
863
941
|
onPost: onPostCallback
|
|
864
942
|
}) {
|
|
865
943
|
var _a, _b;
|
|
866
|
-
const {
|
|
944
|
+
const { showNewsPanel } = useTheme();
|
|
867
945
|
const bottomRef = useRef(null);
|
|
868
946
|
const textareaRef = useRef(null);
|
|
869
947
|
const dropdownRef = useRef(null);
|
|
@@ -876,40 +954,48 @@ function ChatWindow({
|
|
|
876
954
|
const [selectedSource, setSelectedSource] = useState4(null);
|
|
877
955
|
const [loadingSources, setLoadingSources] = useState4(false);
|
|
878
956
|
const [scraping, setScraping] = useState4(false);
|
|
879
|
-
const [editModal, setEditModal] = useState4({ isOpen: false, content: "", metaKeywords: [], messageId: "" });
|
|
957
|
+
const [editModal, setEditModal] = useState4({ isOpen: false, title: "", subtitle: "", content: "", metaDescription: "", metaKeywords: [], messageId: "" });
|
|
880
958
|
const { primaryColor } = useTheme();
|
|
881
959
|
const { preferences } = usePreferences();
|
|
882
960
|
const preferredLanguage = (_a = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _a.language;
|
|
883
|
-
const handleCopy = async (
|
|
961
|
+
const handleCopy = async (parsed, messageId) => {
|
|
884
962
|
try {
|
|
885
|
-
const
|
|
886
|
-
|
|
963
|
+
const tempDiv = document.createElement("div");
|
|
964
|
+
let textContent = "";
|
|
965
|
+
if (parsed.title) textContent += parsed.title + "\n\n";
|
|
966
|
+
if (parsed.subtitle) textContent += parsed.subtitle + "\n\n";
|
|
967
|
+
if (parsed.articleHtml) {
|
|
968
|
+
tempDiv.innerHTML = parsed.articleHtml;
|
|
969
|
+
textContent += tempDiv.textContent || tempDiv.innerText || "";
|
|
970
|
+
}
|
|
971
|
+
if (parsed.metaDescription) textContent += "\n\nMeta Description:\n" + parsed.metaDescription;
|
|
972
|
+
await navigator.clipboard.writeText(textContent);
|
|
887
973
|
setCopiedId(messageId);
|
|
888
974
|
setTimeout(() => setCopiedId(null), 2e3);
|
|
889
975
|
} catch (err) {
|
|
890
976
|
console.error("Failed to copy:", err);
|
|
891
977
|
}
|
|
892
978
|
};
|
|
893
|
-
const
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
979
|
+
const handleEdit = (parsed, messageId) => {
|
|
980
|
+
setEditModal({
|
|
981
|
+
isOpen: true,
|
|
982
|
+
title: parsed.title || "",
|
|
983
|
+
subtitle: parsed.subtitle || "",
|
|
984
|
+
content: parsed.articleHtml || "",
|
|
985
|
+
metaDescription: parsed.metaDescription || "",
|
|
986
|
+
metaKeywords: parsed.metaKeywords,
|
|
987
|
+
messageId
|
|
988
|
+
});
|
|
903
989
|
};
|
|
904
990
|
const handleCloseModal = () => {
|
|
905
|
-
setEditModal({ isOpen: false, content: "", metaKeywords: [], messageId: "" });
|
|
991
|
+
setEditModal({ isOpen: false, title: "", subtitle: "", content: "", metaDescription: "", metaKeywords: [], messageId: "" });
|
|
906
992
|
};
|
|
907
|
-
const handleSaveDraft = (
|
|
908
|
-
console.log("Saving draft:",
|
|
993
|
+
const handleSaveDraft = (data) => {
|
|
994
|
+
console.log("Saving draft:", data);
|
|
909
995
|
handleCloseModal();
|
|
910
996
|
};
|
|
911
|
-
const handlePost = (
|
|
912
|
-
onPostCallback == null ? void 0 : onPostCallback(
|
|
997
|
+
const handlePost = (data) => {
|
|
998
|
+
onPostCallback == null ? void 0 : onPostCallback(data.article, data.keywords);
|
|
913
999
|
handleCloseModal();
|
|
914
1000
|
};
|
|
915
1001
|
useLayoutEffect(() => {
|
|
@@ -998,77 +1084,62 @@ function ChatWindow({
|
|
|
998
1084
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
999
1085
|
};
|
|
1000
1086
|
}, [showNewsDropdown]);
|
|
1001
|
-
function formatAIContent(raw) {
|
|
1002
|
-
const extracted = extractArticleContent(raw);
|
|
1003
|
-
if (!extracted || !extracted.article) {
|
|
1004
|
-
return { blocks: [], metaKeywords: [] };
|
|
1005
|
-
}
|
|
1006
|
-
const { article, metaKeywords } = extracted;
|
|
1007
|
-
const normalized = article.replace(/^H1:\s*/gm, "").replace(/^H2:\s*/gm, "").replace(/<\/h1>/gi, "\n").replace(/<\/h2>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<br\s*\/?>/gi, "\n");
|
|
1008
|
-
const lines = normalized.split("\n").map((line) => line.replace(/<[^>]+>/g, "").trim()).filter(Boolean);
|
|
1009
|
-
const blocks = [];
|
|
1010
|
-
lines.forEach((line, index) => {
|
|
1011
|
-
if (index === 0 && line.length < 120) {
|
|
1012
|
-
blocks.push({ type: "h1", text: line });
|
|
1013
|
-
return;
|
|
1014
|
-
}
|
|
1015
|
-
if (line.length < 90 && !line.endsWith("\u0964") && !line.endsWith(".")) {
|
|
1016
|
-
blocks.push({ type: "h2", text: line });
|
|
1017
|
-
return;
|
|
1018
|
-
}
|
|
1019
|
-
blocks.push({ type: "p", text: line });
|
|
1020
|
-
});
|
|
1021
|
-
return { blocks, metaKeywords };
|
|
1022
|
-
}
|
|
1023
1087
|
return /* @__PURE__ */ jsxs4("div", { className: "cnfy-chat", children: [
|
|
1024
1088
|
/* @__PURE__ */ jsx5("div", { className: "cnfy-chat-area", children: /* @__PURE__ */ jsxs4("div", { className: "cnfy-chat-scroll", children: [
|
|
1025
1089
|
messages.map((msg) => {
|
|
1026
|
-
var _a2;
|
|
1090
|
+
var _a2, _b2;
|
|
1027
1091
|
const parsed = formatAIContent(msg.content);
|
|
1028
1092
|
return /* @__PURE__ */ jsx5("div", { className: "cnfy-msg", children: /* @__PURE__ */ jsxs4("div", { className: msg.role === "assistant" ? `cnfy-msg-body` : `cnfy-msg-body you`, children: [
|
|
1029
|
-
msg.role === "assistant" && parsed.
|
|
1093
|
+
msg.role === "assistant" && parsed.isArticle && /* @__PURE__ */ jsx5("div", { className: "cnfy-msg-copy-row", children: /* @__PURE__ */ jsx5(
|
|
1030
1094
|
"button",
|
|
1031
1095
|
{
|
|
1032
|
-
onClick: () => handleCopy(parsed
|
|
1096
|
+
onClick: () => handleCopy(parsed, msg.id),
|
|
1033
1097
|
className: "cnfy-copy-btn",
|
|
1034
1098
|
title: "Copy to clipboard",
|
|
1035
1099
|
children: copiedId === msg.id ? /* @__PURE__ */ jsx5(Check, { size: 16, className: "cnfy-copy-icon--copied" }) : /* @__PURE__ */ jsx5(Copy, { size: 16 })
|
|
1036
1100
|
}
|
|
1037
1101
|
) }),
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
})
|
|
1061
|
-
|
|
1062
|
-
"
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
},
|
|
1070
|
-
i
|
|
1071
|
-
|
|
1102
|
+
msg.role === "assistant" && isStreaming && msg.id === ((_a2 = messages[messages.length - 1]) == null ? void 0 : _a2.id) && !parsed.isArticle && !parsed.plainText && /* @__PURE__ */ jsxs4("div", { className: "cnfy-creating-indicator", children: [
|
|
1103
|
+
/* @__PURE__ */ jsx5(Loader2, { size: 16, className: "cnfy-animate-spin" }),
|
|
1104
|
+
/* @__PURE__ */ jsx5("span", { children: "Creating article..." })
|
|
1105
|
+
] }),
|
|
1106
|
+
parsed.isArticle ? /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1107
|
+
parsed.title && /* @__PURE__ */ jsxs4("h1", { className: "cnfy-block-h1", children: [
|
|
1108
|
+
parsed.title,
|
|
1109
|
+
activeField === "title" && /* @__PURE__ */ jsx5("span", { className: "cnfy-cursor-blink", children: "|" })
|
|
1110
|
+
] }),
|
|
1111
|
+
parsed.subtitle && /* @__PURE__ */ jsxs4("h1", { className: "cnfy-block-h2", children: [
|
|
1112
|
+
parsed.subtitle,
|
|
1113
|
+
activeField === "subtitle" && /* @__PURE__ */ jsx5("span", { className: "cnfy-cursor-blink", children: "|" })
|
|
1114
|
+
] }),
|
|
1115
|
+
/* @__PURE__ */ jsx5("hr", { className: "cnfy-divider" }),
|
|
1116
|
+
parsed.articleHtml && /* @__PURE__ */ jsx5(
|
|
1117
|
+
"div",
|
|
1118
|
+
{
|
|
1119
|
+
className: "cnfy-article-content",
|
|
1120
|
+
dangerouslySetInnerHTML: { __html: parsed.articleHtml }
|
|
1121
|
+
}
|
|
1122
|
+
),
|
|
1123
|
+
activeField === "article" && /* @__PURE__ */ jsx5("span", { className: "cnfy-cursor-blink", children: "|" })
|
|
1124
|
+
] }) : (
|
|
1125
|
+
/* Plain text messages (status, error, options, etc.) */
|
|
1126
|
+
parsed.plainText && /* @__PURE__ */ jsx5("p", { className: "cnfy-block-p", children: parsed.plainText })
|
|
1127
|
+
),
|
|
1128
|
+
parsed.metaDescription && /* @__PURE__ */ jsxs4("div", { className: "cnfy-msg-keywords", children: [
|
|
1129
|
+
/* @__PURE__ */ jsx5("div", { className: "cnfy-msg-keywords-label", children: "Meta Description" }),
|
|
1130
|
+
/* @__PURE__ */ jsx5("div", { className: "cnfy-block-p", children: parsed.metaDescription })
|
|
1131
|
+
] }),
|
|
1132
|
+
parsed.metaKeywords.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "cnfy-msg-keywords", children: [
|
|
1133
|
+
/* @__PURE__ */ jsx5("div", { className: "cnfy-msg-keywords-label", children: "Keywords" }),
|
|
1134
|
+
/* @__PURE__ */ jsx5("div", { className: "cnfy-msg-keywords-list", children: parsed.metaKeywords.map((tag, i) => /* @__PURE__ */ jsx5(
|
|
1135
|
+
"span",
|
|
1136
|
+
{
|
|
1137
|
+
className: "cnfy-msg-keyword-tag",
|
|
1138
|
+
children: tag
|
|
1139
|
+
},
|
|
1140
|
+
i
|
|
1141
|
+
)) })
|
|
1142
|
+
] }),
|
|
1072
1143
|
msg.role === "assistant" && (analyzedData == null ? void 0 : analyzedData.messageId) === msg.id && analyzedData.options.length > 0 && /* @__PURE__ */ jsx5("div", { className: "cnfy-action-options", children: analyzedData.options.map((option) => {
|
|
1073
1144
|
const IconComponent = ACTION_ICONS[option.id] || FileText;
|
|
1074
1145
|
return /* @__PURE__ */ jsxs4(
|
|
@@ -1084,11 +1155,11 @@ function ChatWindow({
|
|
|
1084
1155
|
option.id
|
|
1085
1156
|
);
|
|
1086
1157
|
}) }),
|
|
1087
|
-
msg.role === "assistant" && parsed.
|
|
1158
|
+
msg.role === "assistant" && parsed.isArticle && !(analyzedData == null ? void 0 : analyzedData.messageId) && (!isStreaming || msg.id !== ((_b2 = messages[messages.length - 1]) == null ? void 0 : _b2.id)) && /* @__PURE__ */ jsxs4("div", { className: "cnfy-msg-actions", children: [
|
|
1088
1159
|
/* @__PURE__ */ jsxs4(
|
|
1089
1160
|
"button",
|
|
1090
1161
|
{
|
|
1091
|
-
onClick: () => handleEdit(parsed
|
|
1162
|
+
onClick: () => handleEdit(parsed, msg.id),
|
|
1092
1163
|
className: "cnfy-btn-edit",
|
|
1093
1164
|
children: [
|
|
1094
1165
|
/* @__PURE__ */ jsx5(Edit3, { size: 16 }),
|
|
@@ -1099,7 +1170,7 @@ function ChatWindow({
|
|
|
1099
1170
|
/* @__PURE__ */ jsxs4(
|
|
1100
1171
|
"button",
|
|
1101
1172
|
{
|
|
1102
|
-
onClick: () => handlePost(
|
|
1173
|
+
onClick: () => handlePost({ article: parsed.articleHtml, keywords: parsed.metaKeywords }),
|
|
1103
1174
|
className: "cnfy-btn-post",
|
|
1104
1175
|
style: { backgroundColor: primaryColor, color: "#fff" },
|
|
1105
1176
|
children: [
|
|
@@ -1241,7 +1312,8 @@ function ChatWindow({
|
|
|
1241
1312
|
rows: 1,
|
|
1242
1313
|
placeholder: "Ask AI something\u2026",
|
|
1243
1314
|
className: `cnfy-chat-textarea ${!showNewsPanel ? "cnfy-chat-textarea--with-pulse" : ""}`,
|
|
1244
|
-
style: { maxHeight: "200px", overflowY: input.split("\n").length > 6 ? "auto" : "hidden" }
|
|
1315
|
+
style: { maxHeight: "200px", overflowY: input.split("\n").length > 6 ? "auto" : "hidden" },
|
|
1316
|
+
disabled: true
|
|
1245
1317
|
}
|
|
1246
1318
|
),
|
|
1247
1319
|
/* @__PURE__ */ jsx5(
|
|
@@ -1258,11 +1330,14 @@ function ChatWindow({
|
|
|
1258
1330
|
EditModal,
|
|
1259
1331
|
{
|
|
1260
1332
|
isOpen: editModal.isOpen,
|
|
1333
|
+
initialTitle: editModal.title,
|
|
1334
|
+
initialSubtitle: editModal.subtitle,
|
|
1261
1335
|
initialContent: editModal.content,
|
|
1336
|
+
initialMetaDescription: editModal.metaDescription,
|
|
1262
1337
|
metaKeywords: editModal.metaKeywords,
|
|
1263
1338
|
onClose: handleCloseModal,
|
|
1264
|
-
onSaveDraft: handleSaveDraft,
|
|
1265
|
-
onPost: handlePost
|
|
1339
|
+
onSaveDraft: (data) => handleSaveDraft({ article: data.article, keywords: data.keywords }),
|
|
1340
|
+
onPost: (data) => handlePost({ article: data.article, keywords: data.keywords })
|
|
1266
1341
|
}
|
|
1267
1342
|
)
|
|
1268
1343
|
] });
|
|
@@ -1377,8 +1452,17 @@ var ClientSelect = (props) => {
|
|
|
1377
1452
|
};
|
|
1378
1453
|
var ClientSelect_default = ClientSelect;
|
|
1379
1454
|
|
|
1455
|
+
// src/utils/util.ts
|
|
1456
|
+
var hexToRgba = (hex, opacity) => {
|
|
1457
|
+
const sanitizedHex = hex.replace("#", "");
|
|
1458
|
+
const r = parseInt(sanitizedHex.substring(0, 2), 16);
|
|
1459
|
+
const g = parseInt(sanitizedHex.substring(2, 4), 16);
|
|
1460
|
+
const b = parseInt(sanitizedHex.substring(4, 6), 16);
|
|
1461
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
1462
|
+
};
|
|
1463
|
+
|
|
1380
1464
|
// components/preferences/Preferences.tsx
|
|
1381
|
-
import { Fragment, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1465
|
+
import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1382
1466
|
var STATE_OPTIONS = [
|
|
1383
1467
|
{ value: "Uttar Pradesh", label: "Uttar Pradesh" }
|
|
1384
1468
|
];
|
|
@@ -1623,7 +1707,7 @@ function PreferencesPage() {
|
|
|
1623
1707
|
/* @__PURE__ */ jsxs7("p", { className: "cnfy-dash-info-text", children: [
|
|
1624
1708
|
"Current configuration: ",
|
|
1625
1709
|
/* @__PURE__ */ jsx10("strong", { children: (_b = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _b.state }),
|
|
1626
|
-
((_c = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _c.cities) && preferences.localization.cities.length > 0 && /* @__PURE__ */ jsxs7(
|
|
1710
|
+
((_c = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _c.cities) && preferences.localization.cities.length > 0 && /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1627
1711
|
" - ",
|
|
1628
1712
|
preferences.localization.cities.join(", ")
|
|
1629
1713
|
] })
|
|
@@ -1695,12 +1779,72 @@ function PreferencesPage() {
|
|
|
1695
1779
|
}
|
|
1696
1780
|
|
|
1697
1781
|
// services/chat.service.ts
|
|
1782
|
+
function getHeaders() {
|
|
1783
|
+
const apiKey = getApiKey();
|
|
1784
|
+
const headers = {
|
|
1785
|
+
"Content-Type": "application/json"
|
|
1786
|
+
};
|
|
1787
|
+
if (apiKey) {
|
|
1788
|
+
headers["x-api-key"] = apiKey;
|
|
1789
|
+
}
|
|
1790
|
+
return headers;
|
|
1791
|
+
}
|
|
1792
|
+
async function processSSEStream(reader, callbacks) {
|
|
1793
|
+
const decoder = new TextDecoder();
|
|
1794
|
+
let buffer = "";
|
|
1795
|
+
const processLines = (lines) => {
|
|
1796
|
+
var _a, _b, _c, _d, _e;
|
|
1797
|
+
for (const line of lines) {
|
|
1798
|
+
const trimmed = line.trim();
|
|
1799
|
+
if (!trimmed.startsWith("data: ")) continue;
|
|
1800
|
+
const data = trimmed.slice(6).trim();
|
|
1801
|
+
try {
|
|
1802
|
+
const event = JSON.parse(data);
|
|
1803
|
+
switch (event.type) {
|
|
1804
|
+
case "start":
|
|
1805
|
+
break;
|
|
1806
|
+
case "field_start":
|
|
1807
|
+
(_a = callbacks.onFieldStart) == null ? void 0 : _a.call(callbacks, event.field);
|
|
1808
|
+
break;
|
|
1809
|
+
case "content":
|
|
1810
|
+
callbacks.onContent(event.field, event.content);
|
|
1811
|
+
break;
|
|
1812
|
+
case "keywords":
|
|
1813
|
+
(_b = callbacks.onKeywords) == null ? void 0 : _b.call(callbacks, event.content);
|
|
1814
|
+
break;
|
|
1815
|
+
case "field_end":
|
|
1816
|
+
(_c = callbacks.onFieldEnd) == null ? void 0 : _c.call(callbacks, event.field);
|
|
1817
|
+
break;
|
|
1818
|
+
case "done":
|
|
1819
|
+
(_d = callbacks.onComplete) == null ? void 0 : _d.call(callbacks, event.data);
|
|
1820
|
+
return true;
|
|
1821
|
+
case "error":
|
|
1822
|
+
(_e = callbacks.onError) == null ? void 0 : _e.call(callbacks, new Error(event.message));
|
|
1823
|
+
return true;
|
|
1824
|
+
}
|
|
1825
|
+
} catch (e) {
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
return false;
|
|
1829
|
+
};
|
|
1830
|
+
while (true) {
|
|
1831
|
+
const { done, value } = await reader.read();
|
|
1832
|
+
if (done) break;
|
|
1833
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1834
|
+
const lines = buffer.split("\n");
|
|
1835
|
+
buffer = lines.pop() || "";
|
|
1836
|
+
if (processLines(lines)) return;
|
|
1837
|
+
}
|
|
1838
|
+
if (buffer.trim()) {
|
|
1839
|
+
processLines([buffer]);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1698
1842
|
var analyzeInputApi = async (input) => {
|
|
1699
|
-
const { data } = await api_default.post("/
|
|
1843
|
+
const { data } = await api_default.post("/chatboat/analyze-input", { input });
|
|
1700
1844
|
return data.data;
|
|
1701
1845
|
};
|
|
1702
1846
|
var createContentApi = async (payload) => {
|
|
1703
|
-
const { data } = await api_default.post("/
|
|
1847
|
+
const { data } = await api_default.post("/chatboat/create-content", payload);
|
|
1704
1848
|
return data.data;
|
|
1705
1849
|
};
|
|
1706
1850
|
var createContentStreamApi = async ({
|
|
@@ -1708,22 +1852,18 @@ var createContentStreamApi = async ({
|
|
|
1708
1852
|
content,
|
|
1709
1853
|
actionId,
|
|
1710
1854
|
settings,
|
|
1711
|
-
|
|
1855
|
+
onFieldStart,
|
|
1856
|
+
onContent,
|
|
1857
|
+
onKeywords,
|
|
1858
|
+
onFieldEnd,
|
|
1712
1859
|
onComplete,
|
|
1713
1860
|
onError
|
|
1714
1861
|
}) => {
|
|
1715
1862
|
var _a;
|
|
1716
1863
|
const API_BASE_URL = getApiBaseUrl();
|
|
1717
|
-
const apiKey = getApiKey();
|
|
1718
|
-
const headers = {
|
|
1719
|
-
"Content-Type": "application/json"
|
|
1720
|
-
};
|
|
1721
|
-
if (apiKey) {
|
|
1722
|
-
headers["x-api-key"] = apiKey;
|
|
1723
|
-
}
|
|
1724
1864
|
const response = await fetch(`${API_BASE_URL}/chat/create-content/stream`, {
|
|
1725
1865
|
method: "POST",
|
|
1726
|
-
headers,
|
|
1866
|
+
headers: getHeaders(),
|
|
1727
1867
|
credentials: "include",
|
|
1728
1868
|
body: JSON.stringify({ url, content, actionId, settings })
|
|
1729
1869
|
});
|
|
@@ -1732,50 +1872,17 @@ var createContentStreamApi = async ({
|
|
|
1732
1872
|
throw new Error(`HTTP error! status: ${response.status} - ${errorText}`);
|
|
1733
1873
|
}
|
|
1734
1874
|
const reader = (_a = response.body) == null ? void 0 : _a.getReader();
|
|
1735
|
-
const decoder = new TextDecoder();
|
|
1736
1875
|
if (!reader) {
|
|
1737
1876
|
throw new Error("No reader available");
|
|
1738
1877
|
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
1748
|
-
buffer += chunk;
|
|
1749
|
-
const lines = buffer.split("\n");
|
|
1750
|
-
buffer = lines.pop() || "";
|
|
1751
|
-
for (const line of lines) {
|
|
1752
|
-
const trimmedLine = line.trim();
|
|
1753
|
-
if (trimmedLine === "") continue;
|
|
1754
|
-
hasReceivedData = true;
|
|
1755
|
-
if (trimmedLine.startsWith("data: ")) {
|
|
1756
|
-
const data = trimmedLine.slice(6).trim();
|
|
1757
|
-
if (data === "[DONE]") {
|
|
1758
|
-
onComplete == null ? void 0 : onComplete();
|
|
1759
|
-
return;
|
|
1760
|
-
}
|
|
1761
|
-
try {
|
|
1762
|
-
const parsed = JSON.parse(data);
|
|
1763
|
-
if (parsed.content) onChunk(parsed.content);
|
|
1764
|
-
else if (parsed.delta) onChunk(parsed.delta);
|
|
1765
|
-
else if (parsed.text) onChunk(parsed.text);
|
|
1766
|
-
else if (parsed.chunk) onChunk(parsed.chunk);
|
|
1767
|
-
else if (typeof parsed === "string") onChunk(parsed);
|
|
1768
|
-
} catch (e) {
|
|
1769
|
-
if (data) onChunk(data);
|
|
1770
|
-
}
|
|
1771
|
-
} else if (trimmedLine) {
|
|
1772
|
-
onChunk(trimmedLine + "\n");
|
|
1773
|
-
}
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1776
|
-
if (!hasReceivedData) {
|
|
1777
|
-
throw new Error("No data received from stream");
|
|
1778
|
-
}
|
|
1878
|
+
await processSSEStream(reader, {
|
|
1879
|
+
onFieldStart,
|
|
1880
|
+
onContent,
|
|
1881
|
+
onKeywords,
|
|
1882
|
+
onFieldEnd,
|
|
1883
|
+
onComplete,
|
|
1884
|
+
onError
|
|
1885
|
+
});
|
|
1779
1886
|
};
|
|
1780
1887
|
var rewriteNewsStreamApi = async ({
|
|
1781
1888
|
article,
|
|
@@ -1787,7 +1894,10 @@ var rewriteNewsStreamApi = async ({
|
|
|
1787
1894
|
includeQuotes,
|
|
1788
1895
|
includeFAQ,
|
|
1789
1896
|
targetAudience,
|
|
1790
|
-
|
|
1897
|
+
onFieldStart,
|
|
1898
|
+
onContent,
|
|
1899
|
+
onKeywords,
|
|
1900
|
+
onFieldEnd,
|
|
1791
1901
|
onComplete,
|
|
1792
1902
|
onError
|
|
1793
1903
|
}) => {
|
|
@@ -1796,9 +1906,7 @@ var rewriteNewsStreamApi = async ({
|
|
|
1796
1906
|
article,
|
|
1797
1907
|
language
|
|
1798
1908
|
};
|
|
1799
|
-
if (articleId)
|
|
1800
|
-
payload.articleId = articleId;
|
|
1801
|
-
}
|
|
1909
|
+
if (articleId) payload.articleId = articleId;
|
|
1802
1910
|
if (tone) payload.tone = tone;
|
|
1803
1911
|
if (style) payload.style = style;
|
|
1804
1912
|
if (wordCount) payload.wordCount = wordCount;
|
|
@@ -1807,99 +1915,42 @@ var rewriteNewsStreamApi = async ({
|
|
|
1807
1915
|
if (targetAudience) payload.targetAudience = targetAudience;
|
|
1808
1916
|
try {
|
|
1809
1917
|
const API_BASE_URL = getApiBaseUrl();
|
|
1810
|
-
const apiKey = getApiKey();
|
|
1811
|
-
const headers = {
|
|
1812
|
-
"Content-Type": "application/json"
|
|
1813
|
-
};
|
|
1814
|
-
if (apiKey) {
|
|
1815
|
-
headers["x-api-key"] = apiKey;
|
|
1816
|
-
}
|
|
1817
1918
|
const response = await fetch(`${API_BASE_URL}/chatboat/rewrite/stream`, {
|
|
1818
1919
|
method: "POST",
|
|
1819
|
-
headers,
|
|
1920
|
+
headers: getHeaders(),
|
|
1820
1921
|
credentials: "include",
|
|
1821
1922
|
body: JSON.stringify(payload)
|
|
1822
1923
|
});
|
|
1823
|
-
console.log("\u{1F4E1} Response status:", response.status);
|
|
1824
|
-
console.log("\u{1F4E1} Response headers:", Object.fromEntries(response.headers.entries()));
|
|
1825
1924
|
if (!response.ok) {
|
|
1826
1925
|
const errorText = await response.text();
|
|
1827
|
-
console.error("\u274C API Error:", response.status, errorText);
|
|
1828
1926
|
throw new Error(`HTTP error! status: ${response.status} - ${errorText}`);
|
|
1829
1927
|
}
|
|
1928
|
+
const contentType = response.headers.get("content-type") || "";
|
|
1929
|
+
if (contentType.includes("application/json")) {
|
|
1930
|
+
const json = await response.json();
|
|
1931
|
+
const data = json.data || json;
|
|
1932
|
+
onComplete == null ? void 0 : onComplete({
|
|
1933
|
+
title: data.title || "",
|
|
1934
|
+
subtitle: data.subtitle || "",
|
|
1935
|
+
article: data.article || "",
|
|
1936
|
+
metaDescription: data.metaDescription || "",
|
|
1937
|
+
metaKeywords: Array.isArray(data.metaKeywords) ? data.metaKeywords : []
|
|
1938
|
+
});
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1830
1941
|
const reader = (_a = response.body) == null ? void 0 : _a.getReader();
|
|
1831
|
-
const decoder = new TextDecoder();
|
|
1832
1942
|
if (!reader) {
|
|
1833
1943
|
throw new Error("No reader available");
|
|
1834
1944
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
}
|
|
1843
|
-
break;
|
|
1844
|
-
}
|
|
1845
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
1846
|
-
buffer += chunk;
|
|
1847
|
-
const lines = buffer.split("\n");
|
|
1848
|
-
buffer = lines.pop() || "";
|
|
1849
|
-
for (const line of lines) {
|
|
1850
|
-
const trimmedLine = line.trim();
|
|
1851
|
-
if (trimmedLine === "") continue;
|
|
1852
|
-
hasReceivedData = true;
|
|
1853
|
-
console.log("\u{1F4E8} Received line:", trimmedLine.substring(0, 100) + (trimmedLine.length > 100 ? "..." : ""));
|
|
1854
|
-
if (trimmedLine.startsWith("data: ")) {
|
|
1855
|
-
const data = trimmedLine.slice(6).trim();
|
|
1856
|
-
if (data === "[DONE]") {
|
|
1857
|
-
console.log("\u2705 Stream completed with [DONE] signal");
|
|
1858
|
-
onComplete == null ? void 0 : onComplete();
|
|
1859
|
-
return;
|
|
1860
|
-
}
|
|
1861
|
-
try {
|
|
1862
|
-
const parsed = JSON.parse(data);
|
|
1863
|
-
console.log("\u{1F4CB} Parsed JSON:", parsed);
|
|
1864
|
-
if (parsed.content) {
|
|
1865
|
-
onChunk(parsed.content);
|
|
1866
|
-
} else if (parsed.delta) {
|
|
1867
|
-
onChunk(parsed.delta);
|
|
1868
|
-
} else if (parsed.text) {
|
|
1869
|
-
onChunk(parsed.text);
|
|
1870
|
-
} else if (parsed.chunk) {
|
|
1871
|
-
onChunk(parsed.chunk);
|
|
1872
|
-
} else if (typeof parsed === "string") {
|
|
1873
|
-
onChunk(parsed);
|
|
1874
|
-
} else {
|
|
1875
|
-
console.warn("\u26A0\uFE0F Unknown JSON format:", parsed);
|
|
1876
|
-
}
|
|
1877
|
-
} catch (e) {
|
|
1878
|
-
console.log("\u{1F4DD} Non-JSON data, treating as plain text");
|
|
1879
|
-
if (data) {
|
|
1880
|
-
onChunk(data);
|
|
1881
|
-
}
|
|
1882
|
-
}
|
|
1883
|
-
} else {
|
|
1884
|
-
console.log("\u{1F4C4} Plain text chunk");
|
|
1885
|
-
if (trimmedLine) {
|
|
1886
|
-
onChunk(trimmedLine + "\n");
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1891
|
-
if (!hasReceivedData) {
|
|
1892
|
-
console.error("\u274C No data received from stream");
|
|
1893
|
-
throw new Error("No data received from stream");
|
|
1894
|
-
}
|
|
1895
|
-
console.log("\u2705 Stream completed successfully");
|
|
1896
|
-
} catch (error) {
|
|
1897
|
-
console.error("\u274C Streaming error:", error);
|
|
1898
|
-
console.error("Error details:", {
|
|
1899
|
-
message: error.message,
|
|
1900
|
-
name: error.name,
|
|
1901
|
-
stack: error.stack
|
|
1945
|
+
await processSSEStream(reader, {
|
|
1946
|
+
onFieldStart,
|
|
1947
|
+
onContent,
|
|
1948
|
+
onKeywords,
|
|
1949
|
+
onFieldEnd,
|
|
1950
|
+
onComplete,
|
|
1951
|
+
onError
|
|
1902
1952
|
});
|
|
1953
|
+
} catch (error) {
|
|
1903
1954
|
onError == null ? void 0 : onError(error);
|
|
1904
1955
|
throw error;
|
|
1905
1956
|
}
|
|
@@ -1919,29 +1970,31 @@ var rewriteNewsApi = async ({
|
|
|
1919
1970
|
article,
|
|
1920
1971
|
language
|
|
1921
1972
|
};
|
|
1922
|
-
if (articleId)
|
|
1923
|
-
payload.articleId = articleId;
|
|
1924
|
-
}
|
|
1973
|
+
if (articleId) payload.articleId = articleId;
|
|
1925
1974
|
if (tone) payload.tone = tone;
|
|
1926
1975
|
if (style) payload.style = style;
|
|
1927
1976
|
if (wordCount) payload.wordCount = wordCount;
|
|
1928
1977
|
if (includeQuotes !== void 0) payload.includeQuotes = includeQuotes;
|
|
1929
1978
|
if (includeFAQ !== void 0) payload.includeFAQ = includeFAQ;
|
|
1930
1979
|
if (targetAudience) payload.targetAudience = targetAudience;
|
|
1931
|
-
const { data } = await api_default.post("/
|
|
1980
|
+
const { data } = await api_default.post("/chatboat/rewrite", payload);
|
|
1932
1981
|
return data.data;
|
|
1933
1982
|
};
|
|
1934
1983
|
|
|
1935
1984
|
// components/chatbot/ChatBot.tsx
|
|
1936
1985
|
import toast2 from "react-hot-toast";
|
|
1937
|
-
import { Loader2 } from "lucide-react";
|
|
1986
|
+
import { Loader2 as Loader22 } from "lucide-react";
|
|
1938
1987
|
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1988
|
+
function buildStructuredContent(title, article, metaKeywords, subtitle = "", metaDescription = "") {
|
|
1989
|
+
return JSON.stringify({ title, subtitle, article, metaDescription, metaKeywords });
|
|
1990
|
+
}
|
|
1939
1991
|
function ChatBot({ onPost }) {
|
|
1940
1992
|
const { loading } = useTheme();
|
|
1941
1993
|
const { preferences } = usePreferences();
|
|
1942
1994
|
const [preferencesOpen, setPreferencesOpen] = useState7(false);
|
|
1943
1995
|
const [messages, setMessages] = useState7([]);
|
|
1944
1996
|
const [isStreaming, setIsStreaming] = useState7(false);
|
|
1997
|
+
const [activeField, setActiveField] = useState7(null);
|
|
1945
1998
|
const [analyzedData, setAnalyzedData] = useState7(null);
|
|
1946
1999
|
const handleRecreate = async ({ title, content, id }) => {
|
|
1947
2000
|
var _a;
|
|
@@ -1952,17 +2005,28 @@ function ChatBot({ onPost }) {
|
|
|
1952
2005
|
id: crypto.randomUUID(),
|
|
1953
2006
|
role: "user",
|
|
1954
2007
|
content: `Recreate this news:
|
|
1955
|
-
${title}`
|
|
2008
|
+
${title}`
|
|
1956
2009
|
},
|
|
1957
2010
|
{
|
|
1958
2011
|
id: assistantId,
|
|
1959
2012
|
role: "assistant",
|
|
1960
|
-
content: "
|
|
2013
|
+
content: ""
|
|
1961
2014
|
}
|
|
1962
2015
|
]);
|
|
2016
|
+
setIsStreaming(true);
|
|
1963
2017
|
try {
|
|
1964
|
-
let accumulatedContent = "";
|
|
1965
2018
|
let hasStartedStreaming = false;
|
|
2019
|
+
let titleBuffer = "";
|
|
2020
|
+
let articleBuffer = "";
|
|
2021
|
+
let keywordsBuffer = [];
|
|
2022
|
+
const updateMessage = () => {
|
|
2023
|
+
const structured = buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer);
|
|
2024
|
+
setMessages(
|
|
2025
|
+
(prev) => prev.map(
|
|
2026
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: structured }) : m
|
|
2027
|
+
)
|
|
2028
|
+
);
|
|
2029
|
+
};
|
|
1966
2030
|
const contentPrefs = preferences == null ? void 0 : preferences.content;
|
|
1967
2031
|
const lang = ((_a = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _a.language) === "hi" ? "Hindi" : "English";
|
|
1968
2032
|
try {
|
|
@@ -1976,39 +2040,66 @@ ${title}`
|
|
|
1976
2040
|
includeQuotes: contentPrefs == null ? void 0 : contentPrefs.includeQuotes,
|
|
1977
2041
|
includeFAQ: contentPrefs == null ? void 0 : contentPrefs.includeFAQ,
|
|
1978
2042
|
targetAudience: contentPrefs == null ? void 0 : contentPrefs.targetAudience,
|
|
1979
|
-
|
|
2043
|
+
onFieldStart: (field) => {
|
|
2044
|
+
setActiveField(field);
|
|
2045
|
+
},
|
|
2046
|
+
onContent: (field, chunk) => {
|
|
1980
2047
|
hasStartedStreaming = true;
|
|
1981
|
-
|
|
2048
|
+
if (field === "title") titleBuffer += chunk;
|
|
2049
|
+
else articleBuffer += chunk;
|
|
2050
|
+
updateMessage();
|
|
2051
|
+
},
|
|
2052
|
+
onKeywords: (keywords) => {
|
|
2053
|
+
keywordsBuffer = keywords;
|
|
2054
|
+
updateMessage();
|
|
2055
|
+
},
|
|
2056
|
+
onFieldEnd: () => {
|
|
2057
|
+
setActiveField(null);
|
|
2058
|
+
},
|
|
2059
|
+
onComplete: (data) => {
|
|
2060
|
+
const finalContent = data && (data.title || data.article) ? JSON.stringify(data) : buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer);
|
|
1982
2061
|
setMessages(
|
|
1983
2062
|
(prev) => prev.map(
|
|
1984
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content:
|
|
2063
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: finalContent }) : m
|
|
1985
2064
|
)
|
|
1986
2065
|
);
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
console.log("Streaming completed successfully");
|
|
2066
|
+
setIsStreaming(false);
|
|
2067
|
+
setActiveField(null);
|
|
1990
2068
|
toast2.success("Article created successfully!");
|
|
1991
2069
|
},
|
|
1992
2070
|
onError: async (error) => {
|
|
1993
2071
|
console.error("Streaming error:", error);
|
|
1994
2072
|
if (!hasStartedStreaming) {
|
|
1995
|
-
console.log("Falling back to regular API...");
|
|
1996
2073
|
throw error;
|
|
1997
2074
|
} else {
|
|
2075
|
+
setIsStreaming(false);
|
|
2076
|
+
setActiveField(null);
|
|
1998
2077
|
toast2.error("Failed to complete article generation");
|
|
1999
2078
|
setMessages(
|
|
2000
2079
|
(prev) => prev.map(
|
|
2001
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content:
|
|
2080
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: titleBuffer || articleBuffer ? buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer) : "Failed to create article. Please try again." }) : m
|
|
2002
2081
|
)
|
|
2003
2082
|
);
|
|
2004
2083
|
}
|
|
2005
2084
|
}
|
|
2006
2085
|
});
|
|
2086
|
+
if (isStreaming) {
|
|
2087
|
+
if (titleBuffer || articleBuffer) {
|
|
2088
|
+
const structured = buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer);
|
|
2089
|
+
setMessages(
|
|
2090
|
+
(prev) => prev.map(
|
|
2091
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: structured }) : m
|
|
2092
|
+
)
|
|
2093
|
+
);
|
|
2094
|
+
}
|
|
2095
|
+
setIsStreaming(false);
|
|
2096
|
+
setActiveField(null);
|
|
2097
|
+
}
|
|
2007
2098
|
} catch (streamError) {
|
|
2008
2099
|
console.log("Streaming failed, using regular API...", streamError);
|
|
2009
2100
|
setMessages(
|
|
2010
2101
|
(prev) => prev.map(
|
|
2011
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "
|
|
2102
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "" }) : m
|
|
2012
2103
|
)
|
|
2013
2104
|
);
|
|
2014
2105
|
const result = await rewriteNewsApi({
|
|
@@ -2024,17 +2115,20 @@ ${title}`
|
|
|
2024
2115
|
});
|
|
2025
2116
|
setMessages(
|
|
2026
2117
|
(prev) => prev.map(
|
|
2027
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: result
|
|
2118
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: typeof result === "string" ? result : JSON.stringify(result) }) : m
|
|
2028
2119
|
)
|
|
2029
2120
|
);
|
|
2121
|
+
setIsStreaming(false);
|
|
2030
2122
|
toast2.success("Article created successfully!");
|
|
2031
2123
|
}
|
|
2032
2124
|
} catch (err) {
|
|
2033
2125
|
console.error("Complete Error:", err);
|
|
2126
|
+
setIsStreaming(false);
|
|
2127
|
+
setActiveField(null);
|
|
2034
2128
|
toast2.error((err == null ? void 0 : err.message) || "An error occurred while creating the article");
|
|
2035
2129
|
setMessages(
|
|
2036
2130
|
(prev) => prev.map(
|
|
2037
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "
|
|
2131
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "Failed to create article. Please try again." }) : m
|
|
2038
2132
|
)
|
|
2039
2133
|
);
|
|
2040
2134
|
}
|
|
@@ -2052,9 +2146,10 @@ ${title}`
|
|
|
2052
2146
|
if (hasUrl) {
|
|
2053
2147
|
setMessages((prev) => [
|
|
2054
2148
|
...prev,
|
|
2055
|
-
{ id: assistantId, role: "assistant", content: "
|
|
2149
|
+
{ id: assistantId, role: "assistant", content: "Analyzing your link..." }
|
|
2056
2150
|
]);
|
|
2057
2151
|
try {
|
|
2152
|
+
return;
|
|
2058
2153
|
const result = await analyzeInputApi(text);
|
|
2059
2154
|
if (result.hasUrl && ((_a = result.options) == null ? void 0 : _a.length) > 0) {
|
|
2060
2155
|
setAnalyzedData({
|
|
@@ -2085,20 +2180,30 @@ ${optionsList}`
|
|
|
2085
2180
|
toast2.error("Failed to analyze the link");
|
|
2086
2181
|
setMessages(
|
|
2087
2182
|
(prev) => prev.map(
|
|
2088
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "
|
|
2183
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "Failed to analyze the link. Please try again." }) : m
|
|
2089
2184
|
)
|
|
2090
2185
|
);
|
|
2091
2186
|
}
|
|
2092
2187
|
} else {
|
|
2093
2188
|
setMessages((prev) => [
|
|
2094
2189
|
...prev,
|
|
2095
|
-
{ id: assistantId, role: "assistant", content: "
|
|
2190
|
+
{ id: assistantId, role: "assistant", content: "" }
|
|
2096
2191
|
]);
|
|
2097
2192
|
setIsStreaming(true);
|
|
2098
2193
|
try {
|
|
2099
2194
|
const contentPrefs = preferences == null ? void 0 : preferences.content;
|
|
2100
2195
|
const lang = ((_b = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _b.language) === "hi" ? "Hindi" : "English";
|
|
2101
|
-
let
|
|
2196
|
+
let titleBuffer = "";
|
|
2197
|
+
let articleBuffer = "";
|
|
2198
|
+
let keywordsBuffer = [];
|
|
2199
|
+
const updateMessage = () => {
|
|
2200
|
+
const structured = buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer);
|
|
2201
|
+
setMessages(
|
|
2202
|
+
(prev) => prev.map(
|
|
2203
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: structured }) : m
|
|
2204
|
+
)
|
|
2205
|
+
);
|
|
2206
|
+
};
|
|
2102
2207
|
await rewriteNewsStreamApi({
|
|
2103
2208
|
article: text,
|
|
2104
2209
|
language: lang,
|
|
@@ -2108,30 +2213,58 @@ ${optionsList}`
|
|
|
2108
2213
|
includeQuotes: contentPrefs == null ? void 0 : contentPrefs.includeQuotes,
|
|
2109
2214
|
includeFAQ: contentPrefs == null ? void 0 : contentPrefs.includeFAQ,
|
|
2110
2215
|
targetAudience: contentPrefs == null ? void 0 : contentPrefs.targetAudience,
|
|
2111
|
-
|
|
2112
|
-
|
|
2216
|
+
onFieldStart: (field) => {
|
|
2217
|
+
setActiveField(field);
|
|
2218
|
+
},
|
|
2219
|
+
onContent: (field, chunk) => {
|
|
2220
|
+
if (field === "title") titleBuffer += chunk;
|
|
2221
|
+
else articleBuffer += chunk;
|
|
2222
|
+
updateMessage();
|
|
2223
|
+
},
|
|
2224
|
+
onKeywords: (keywords) => {
|
|
2225
|
+
keywordsBuffer = keywords;
|
|
2226
|
+
updateMessage();
|
|
2227
|
+
},
|
|
2228
|
+
onFieldEnd: () => {
|
|
2229
|
+
setActiveField(null);
|
|
2230
|
+
},
|
|
2231
|
+
onComplete: (data) => {
|
|
2232
|
+
const finalContent = data && (data.title || data.article) ? JSON.stringify(data) : buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer);
|
|
2113
2233
|
setMessages(
|
|
2114
2234
|
(prev) => prev.map(
|
|
2115
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content:
|
|
2235
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: finalContent }) : m
|
|
2116
2236
|
)
|
|
2117
2237
|
);
|
|
2118
|
-
},
|
|
2119
|
-
onComplete: () => {
|
|
2120
2238
|
setIsStreaming(false);
|
|
2239
|
+
setActiveField(null);
|
|
2121
2240
|
toast2.success("Content generated!");
|
|
2122
2241
|
},
|
|
2123
2242
|
onError: (error) => {
|
|
2124
2243
|
console.error("Stream error:", error);
|
|
2125
2244
|
setIsStreaming(false);
|
|
2245
|
+
setActiveField(null);
|
|
2126
2246
|
toast2.error("Failed to generate content");
|
|
2127
2247
|
}
|
|
2128
2248
|
});
|
|
2249
|
+
if (isStreaming) {
|
|
2250
|
+
if (titleBuffer || articleBuffer) {
|
|
2251
|
+
const structured = buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer);
|
|
2252
|
+
setMessages(
|
|
2253
|
+
(prev) => prev.map(
|
|
2254
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: structured }) : m
|
|
2255
|
+
)
|
|
2256
|
+
);
|
|
2257
|
+
}
|
|
2258
|
+
setIsStreaming(false);
|
|
2259
|
+
setActiveField(null);
|
|
2260
|
+
}
|
|
2129
2261
|
} catch (err) {
|
|
2130
2262
|
console.error("Send message error:", err);
|
|
2131
2263
|
setIsStreaming(false);
|
|
2264
|
+
setActiveField(null);
|
|
2132
2265
|
setMessages(
|
|
2133
2266
|
(prev) => prev.map(
|
|
2134
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "
|
|
2267
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "Failed to generate content. Please try again." }) : m
|
|
2135
2268
|
)
|
|
2136
2269
|
);
|
|
2137
2270
|
}
|
|
@@ -2145,12 +2278,22 @@ ${optionsList}`
|
|
|
2145
2278
|
setMessages((prev) => [
|
|
2146
2279
|
...prev,
|
|
2147
2280
|
{ id: crypto.randomUUID(), role: "user", content: `Action: ${actionName}` },
|
|
2148
|
-
{ id: assistantId, role: "assistant", content: "
|
|
2281
|
+
{ id: assistantId, role: "assistant", content: "" }
|
|
2149
2282
|
]);
|
|
2150
2283
|
setIsStreaming(true);
|
|
2151
2284
|
try {
|
|
2152
2285
|
const contentPrefs = preferences == null ? void 0 : preferences.content;
|
|
2153
|
-
let
|
|
2286
|
+
let titleBuffer = "";
|
|
2287
|
+
let articleBuffer = "";
|
|
2288
|
+
let keywordsBuffer = [];
|
|
2289
|
+
const updateMessage = () => {
|
|
2290
|
+
const structured = buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer);
|
|
2291
|
+
setMessages(
|
|
2292
|
+
(prev) => prev.map(
|
|
2293
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: structured }) : m
|
|
2294
|
+
)
|
|
2295
|
+
);
|
|
2296
|
+
};
|
|
2154
2297
|
try {
|
|
2155
2298
|
await createContentStreamApi({
|
|
2156
2299
|
url,
|
|
@@ -2161,24 +2304,51 @@ ${optionsList}`
|
|
|
2161
2304
|
style: contentPrefs == null ? void 0 : contentPrefs.style,
|
|
2162
2305
|
wordCount: contentPrefs == null ? void 0 : contentPrefs.wordCount
|
|
2163
2306
|
},
|
|
2164
|
-
|
|
2165
|
-
|
|
2307
|
+
onFieldStart: (field) => {
|
|
2308
|
+
setActiveField(field);
|
|
2309
|
+
},
|
|
2310
|
+
onContent: (field, chunk) => {
|
|
2311
|
+
if (field === "title") titleBuffer += chunk;
|
|
2312
|
+
else articleBuffer += chunk;
|
|
2313
|
+
updateMessage();
|
|
2314
|
+
},
|
|
2315
|
+
onKeywords: (keywords) => {
|
|
2316
|
+
keywordsBuffer = keywords;
|
|
2317
|
+
updateMessage();
|
|
2318
|
+
},
|
|
2319
|
+
onFieldEnd: () => {
|
|
2320
|
+
setActiveField(null);
|
|
2321
|
+
},
|
|
2322
|
+
onComplete: (data) => {
|
|
2323
|
+
const finalContent = data && (data.title || data.article) ? JSON.stringify(data) : buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer);
|
|
2166
2324
|
setMessages(
|
|
2167
2325
|
(prev) => prev.map(
|
|
2168
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content:
|
|
2326
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: finalContent }) : m
|
|
2169
2327
|
)
|
|
2170
2328
|
);
|
|
2171
|
-
},
|
|
2172
|
-
onComplete: () => {
|
|
2173
2329
|
setIsStreaming(false);
|
|
2330
|
+
setActiveField(null);
|
|
2174
2331
|
toast2.success("Content created!");
|
|
2175
2332
|
},
|
|
2176
2333
|
onError: (error) => {
|
|
2177
2334
|
console.error("Stream error:", error);
|
|
2178
2335
|
setIsStreaming(false);
|
|
2336
|
+
setActiveField(null);
|
|
2179
2337
|
toast2.error("Failed to create content");
|
|
2180
2338
|
}
|
|
2181
2339
|
});
|
|
2340
|
+
if (isStreaming) {
|
|
2341
|
+
if (titleBuffer || articleBuffer) {
|
|
2342
|
+
const structured = buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer);
|
|
2343
|
+
setMessages(
|
|
2344
|
+
(prev) => prev.map(
|
|
2345
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: structured }) : m
|
|
2346
|
+
)
|
|
2347
|
+
);
|
|
2348
|
+
}
|
|
2349
|
+
setIsStreaming(false);
|
|
2350
|
+
setActiveField(null);
|
|
2351
|
+
}
|
|
2182
2352
|
} catch (e) {
|
|
2183
2353
|
const result = await createContentApi({ url, content, actionId, settings: {
|
|
2184
2354
|
tone: contentPrefs == null ? void 0 : contentPrefs.tone,
|
|
@@ -2187,25 +2357,27 @@ ${optionsList}`
|
|
|
2187
2357
|
} });
|
|
2188
2358
|
setMessages(
|
|
2189
2359
|
(prev) => prev.map(
|
|
2190
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: result
|
|
2360
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: typeof result === "string" ? result : JSON.stringify(result) }) : m
|
|
2191
2361
|
)
|
|
2192
2362
|
);
|
|
2193
2363
|
setIsStreaming(false);
|
|
2364
|
+
setActiveField(null);
|
|
2194
2365
|
toast2.success("Content created!");
|
|
2195
2366
|
}
|
|
2196
2367
|
} catch (err) {
|
|
2197
2368
|
console.error("Create content error:", err);
|
|
2198
2369
|
setIsStreaming(false);
|
|
2370
|
+
setActiveField(null);
|
|
2199
2371
|
setMessages(
|
|
2200
2372
|
(prev) => prev.map(
|
|
2201
|
-
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "
|
|
2373
|
+
(m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "Failed to create content. Please try again." }) : m
|
|
2202
2374
|
)
|
|
2203
2375
|
);
|
|
2204
2376
|
}
|
|
2205
2377
|
};
|
|
2206
2378
|
if (loading) {
|
|
2207
2379
|
return /* @__PURE__ */ jsx11("div", { className: "cnfy-loading", children: /* @__PURE__ */ jsxs8("div", { className: "cnfy-loading-inner", children: [
|
|
2208
|
-
/* @__PURE__ */ jsx11(
|
|
2380
|
+
/* @__PURE__ */ jsx11(Loader22, { className: "cnfy-loading-spinner cnfy-animate-spin" }),
|
|
2209
2381
|
/* @__PURE__ */ jsx11("p", { className: "cnfy-loading-text", children: "Loading..." })
|
|
2210
2382
|
] }) });
|
|
2211
2383
|
}
|
|
@@ -2219,6 +2391,7 @@ ${optionsList}`
|
|
|
2219
2391
|
onSend: handleSendMessage,
|
|
2220
2392
|
onSelectNews: handleRecreate,
|
|
2221
2393
|
isStreaming,
|
|
2394
|
+
activeField,
|
|
2222
2395
|
analyzedData,
|
|
2223
2396
|
onSelectAction: handleSelectAction,
|
|
2224
2397
|
onPost
|