@contenify/chatbot 1.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/dist/index.mjs CHANGED
@@ -77,7 +77,7 @@ var api_default = api;
77
77
 
78
78
  // services/preferences.service.ts
79
79
  var getMyPreferencesApi = async () => {
80
- const { data } = await api_default.get("/preferences/me");
80
+ const { data } = await api_default.get("/chatboat/preferences/me");
81
81
  return data.data;
82
82
  };
83
83
  var savePreferencesApi = async ({
@@ -155,7 +155,7 @@ var savePreferencesApi = async ({
155
155
  if (targetAudience !== void 0) {
156
156
  formData.append("targetAudience", targetAudience);
157
157
  }
158
- const { data } = await api_default.put("/preferences", formData, {
158
+ const { data } = await api_default.put("/chatboat/preferences", formData, {
159
159
  headers: {
160
160
  "Content-Type": "multipart/form-data"
161
161
  }
@@ -167,7 +167,7 @@ var savePreferencesApi = async ({
167
167
  import { jsx } from "react/jsx-runtime";
168
168
  var defaultPreferences = {
169
169
  chatbot: {
170
- name: "AI News Assistant",
170
+ name: "ContenifyAI Assistant",
171
171
  primaryColor: "#10b981",
172
172
  secondaryColor: "#064e3b",
173
173
  theme: "system"
@@ -266,35 +266,83 @@ function usePreferences() {
266
266
  // components/chatbot/ChatBot.tsx
267
267
  import { useState as useState7 } from "react";
268
268
 
269
- // util/util.ts
270
- function extractArticleContent(raw) {
271
- if (!raw) {
272
- return { article: "", metaKeywords: [] };
273
- }
274
- if (!raw.trim().startsWith("{")) {
275
- return {
276
- article: raw,
277
- metaKeywords: []
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
- const parsed = JSON.parse(raw);
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
- const article = raw.replace(/^[\s\S]*?"article"\s*:\s*"/, "").replace(/"\s*,\s*"metaKeywords"[\s\S]*$/, "").replace(/"}\s*$/, "") || raw;
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
- article,
291
- metaKeywords: []
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
343
 
296
344
  // components/chatbot/ChatWindow.tsx
297
- 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";
298
346
  import { useLayoutEffect, useRef, useState as useState4, useEffect as useEffect4 } from "react";
299
347
 
300
348
  // components/chatbot/EditModal.tsx
@@ -483,38 +531,38 @@ function useTheme() {
483
531
 
484
532
  // components/chatbot/EditModal.tsx
485
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
+ }
486
537
  function EditModal({
487
538
  isOpen,
539
+ initialTitle = "",
540
+ initialSubtitle = "",
488
541
  initialContent,
542
+ initialMetaDescription = "",
489
543
  metaKeywords,
490
544
  onClose,
491
545
  onSaveDraft,
492
546
  onPost
493
547
  }) {
494
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("");
495
554
  const [content, setContent] = useState2("");
496
555
  const [keywords, setKeywords] = useState2(metaKeywords);
497
556
  const [newKeyword, setNewKeyword] = useState2("");
498
- const markdownToHtml = (text) => {
499
- const lines = text.split("\n").filter((line) => line.trim());
500
- let html = "";
501
- lines.forEach((line) => {
502
- const trimmed = line.trim();
503
- if (trimmed.startsWith("# ")) {
504
- html += `<h1>${trimmed.replace(/^#\s+/, "")}</h1>`;
505
- } else if (trimmed.startsWith("## ")) {
506
- html += `<h2>${trimmed.replace(/^##\s+/, "")}</h2>`;
507
- } else {
508
- html += `<p>${trimmed}</p>`;
509
- }
510
- });
511
- return html;
512
- };
513
557
  useEffect3(() => {
514
- const htmlContent = markdownToHtml(initialContent);
515
- setContent(htmlContent);
558
+ setTitle(initialTitle);
559
+ setSubtitle(initialSubtitle);
560
+ setMetaDescription(initialMetaDescription);
561
+ setSlug(toSlug(initialTitle));
562
+ setSlugEdited(false);
563
+ setContent(initialContent);
516
564
  setKeywords(metaKeywords);
517
- }, [initialContent, metaKeywords]);
565
+ }, [initialTitle, initialSubtitle, initialContent, initialMetaDescription, metaKeywords]);
518
566
  useEffect3(() => {
519
567
  if (isOpen) {
520
568
  document.body.style.overflow = "hidden";
@@ -525,6 +573,16 @@ function EditModal({
525
573
  document.body.style.overflow = "";
526
574
  };
527
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
+ };
528
586
  const handleAddKeyword = () => {
529
587
  if (newKeyword.trim() && !keywords.includes(newKeyword.trim())) {
530
588
  setKeywords([...keywords, newKeyword.trim()]);
@@ -540,28 +598,62 @@ function EditModal({
540
598
  handleAddKeyword();
541
599
  }
542
600
  };
601
+ const getEditData = () => ({
602
+ title,
603
+ subtitle,
604
+ article: content,
605
+ metaDescription,
606
+ slug,
607
+ keywords
608
+ });
543
609
  if (!isOpen) return null;
544
610
  return /* @__PURE__ */ jsxs2("div", { className: "cnfy-edit-modal-overlay", children: [
545
- /* @__PURE__ */ jsx3(
546
- "div",
547
- {
548
- className: "cnfy-edit-modal-backdrop",
549
- onClick: onClose
550
- }
551
- ),
611
+ /* @__PURE__ */ jsx3("div", { className: "cnfy-edit-modal-backdrop", onClick: onClose }),
552
612
  /* @__PURE__ */ jsxs2("div", { className: "cnfy-edit-modal", children: [
553
613
  /* @__PURE__ */ jsxs2("div", { className: "cnfy-edit-modal-header", children: [
554
614
  /* @__PURE__ */ jsx3("h2", { className: "cnfy-edit-modal-title", children: "Edit Article" }),
555
- /* @__PURE__ */ jsx3(
556
- "button",
557
- {
558
- onClick: onClose,
559
- className: "cnfy-edit-modal-close-btn",
560
- children: /* @__PURE__ */ jsx3(X, { size: 20, className: "cnfy-edit-modal-close-icon" })
561
- }
562
- )
615
+ /* @__PURE__ */ jsx3("button", { onClick: onClose, className: "cnfy-edit-modal-close-btn", children: /* @__PURE__ */ jsx3(X, { size: 20, className: "cnfy-edit-modal-close-icon" }) })
563
616
  ] }),
564
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
+ ] }),
565
657
  /* @__PURE__ */ jsxs2("div", { children: [
566
658
  /* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Article Content" }),
567
659
  /* @__PURE__ */ jsx3(
@@ -574,26 +666,32 @@ function EditModal({
574
666
  )
575
667
  ] }),
576
668
  /* @__PURE__ */ jsxs2("div", { children: [
577
- /* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Meta Keywords" }),
578
- /* @__PURE__ */ jsx3("div", { className: "cnfy-keyword-list", children: keywords.map((keyword, index) => /* @__PURE__ */ jsxs2(
579
- "span",
669
+ /* @__PURE__ */ jsx3("label", { className: "cnfy-edit-label", children: "Meta Description" }),
670
+ /* @__PURE__ */ jsx3(
671
+ "textarea",
580
672
  {
581
- className: "cnfy-keyword-tag",
582
- children: [
583
- "#",
584
- keyword,
585
- /* @__PURE__ */ jsx3(
586
- "button",
587
- {
588
- onClick: () => handleRemoveKeyword(index),
589
- className: "cnfy-keyword-remove-btn",
590
- children: /* @__PURE__ */ jsx3(X, { size: 14 })
591
- }
592
- )
593
- ]
594
- },
595
- index
596
- )) }),
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)) }),
597
695
  /* @__PURE__ */ jsxs2("div", { className: "cnfy-keyword-input-row", children: [
598
696
  /* @__PURE__ */ jsx3(
599
697
  "input",
@@ -606,30 +704,16 @@ function EditModal({
606
704
  className: "cnfy-keyword-input"
607
705
  }
608
706
  ),
609
- /* @__PURE__ */ jsx3(
610
- "button",
611
- {
612
- onClick: handleAddKeyword,
613
- className: "cnfy-btn-add-keyword",
614
- children: "Add"
615
- }
616
- )
707
+ /* @__PURE__ */ jsx3("button", { onClick: handleAddKeyword, className: "cnfy-btn-add-keyword", children: "Add" })
617
708
  ] })
618
709
  ] })
619
710
  ] }),
620
711
  /* @__PURE__ */ jsxs2("div", { className: "cnfy-edit-modal-footer", children: [
712
+ /* @__PURE__ */ jsx3("button", { onClick: onClose, className: "cnfy-btn-footer-cancel", children: "Cancel" }),
621
713
  /* @__PURE__ */ jsx3(
622
714
  "button",
623
715
  {
624
- onClick: onClose,
625
- className: "cnfy-btn-footer-cancel",
626
- children: "Cancel"
627
- }
628
- ),
629
- /* @__PURE__ */ jsx3(
630
- "button",
631
- {
632
- onClick: () => onSaveDraft(content, keywords),
716
+ onClick: () => onSaveDraft(getEditData()),
633
717
  className: "cnfy-btn-save-draft",
634
718
  children: "Save Draft"
635
719
  }
@@ -637,7 +721,7 @@ function EditModal({
637
721
  /* @__PURE__ */ jsx3(
638
722
  "button",
639
723
  {
640
- onClick: () => onPost(content, keywords),
724
+ onClick: () => onPost(getEditData()),
641
725
  className: "cnfy-btn-post-article",
642
726
  style: { backgroundColor: primaryColor, color: "#fff" },
643
727
  children: "Post"
@@ -819,25 +903,25 @@ function NewsList({
819
903
 
820
904
  // services/news.service.ts
821
905
  var getTrendingNews = async () => {
822
- const { data } = await api_default.get("/news/trending");
906
+ const { data } = await api_default.get("/chatboat/trending");
823
907
  return data.data;
824
908
  };
825
909
  var getNewsSources = async () => {
826
- const { data } = await api_default.get("/news/sources");
910
+ const { data } = await api_default.get("/chatboat/scrape/sources");
827
911
  return data.data;
828
912
  };
829
913
  var scrapeNewsSource = async (sourceId) => {
830
- const { data } = await api_default.post("/news/scrape-source", { sourceId });
914
+ const { data } = await api_default.post("/chatboat/scrape/source", { sourceId });
831
915
  return data.data;
832
916
  };
833
917
  var getNewsBySource = async (sourceId) => {
834
- const { data } = await api_default.get(`/news/by-source/${sourceId}`);
918
+ const { data } = await api_default.get(`/chatboat/scrape/by-source/${sourceId}`);
835
919
  return data.data;
836
920
  };
837
921
 
838
922
  // components/chatbot/ChatWindow.tsx
839
923
  import Select from "react-select";
840
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
924
+ import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
841
925
  var ACTION_ICONS = {
842
926
  recreate_article: RefreshCcw2,
843
927
  create_summary: ListChecks,
@@ -851,12 +935,13 @@ function ChatWindow({
851
935
  onSend,
852
936
  onSelectNews,
853
937
  isStreaming = false,
938
+ activeField,
854
939
  analyzedData,
855
940
  onSelectAction,
856
941
  onPost: onPostCallback
857
942
  }) {
858
943
  var _a, _b;
859
- const { loading, showNewsPanel } = useTheme();
944
+ const { showNewsPanel } = useTheme();
860
945
  const bottomRef = useRef(null);
861
946
  const textareaRef = useRef(null);
862
947
  const dropdownRef = useRef(null);
@@ -869,40 +954,48 @@ function ChatWindow({
869
954
  const [selectedSource, setSelectedSource] = useState4(null);
870
955
  const [loadingSources, setLoadingSources] = useState4(false);
871
956
  const [scraping, setScraping] = useState4(false);
872
- const [editModal, setEditModal] = useState4({ isOpen: false, content: "", metaKeywords: [], messageId: "" });
957
+ const [editModal, setEditModal] = useState4({ isOpen: false, title: "", subtitle: "", content: "", metaDescription: "", metaKeywords: [], messageId: "" });
873
958
  const { primaryColor } = useTheme();
874
959
  const { preferences } = usePreferences();
875
960
  const preferredLanguage = (_a = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _a.language;
876
- const handleCopy = async (blocks, messageId) => {
961
+ const handleCopy = async (parsed, messageId) => {
877
962
  try {
878
- const formattedText = blocksToFormattedText(blocks);
879
- await navigator.clipboard.writeText(formattedText);
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);
880
973
  setCopiedId(messageId);
881
974
  setTimeout(() => setCopiedId(null), 2e3);
882
975
  } catch (err) {
883
976
  console.error("Failed to copy:", err);
884
977
  }
885
978
  };
886
- const blocksToFormattedText = (blocks) => {
887
- return blocks.map((block) => {
888
- if (block.type === "h1") return `# ${block.text}`;
889
- if (block.type === "h2") return `## ${block.text}`;
890
- return block.text;
891
- }).join("\n\n");
892
- };
893
- const handleEdit = (blocks, metaKeywords, messageId) => {
894
- const formattedContent = blocksToFormattedText(blocks);
895
- setEditModal({ isOpen: true, content: formattedContent, metaKeywords, messageId });
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
+ });
896
989
  };
897
990
  const handleCloseModal = () => {
898
- setEditModal({ isOpen: false, content: "", metaKeywords: [], messageId: "" });
991
+ setEditModal({ isOpen: false, title: "", subtitle: "", content: "", metaDescription: "", metaKeywords: [], messageId: "" });
899
992
  };
900
- const handleSaveDraft = (content, keywords) => {
901
- console.log("Saving draft:", { content, keywords });
993
+ const handleSaveDraft = (data) => {
994
+ console.log("Saving draft:", data);
902
995
  handleCloseModal();
903
996
  };
904
- const handlePost = (content, keywords) => {
905
- onPostCallback == null ? void 0 : onPostCallback(content, keywords);
997
+ const handlePost = (data) => {
998
+ onPostCallback == null ? void 0 : onPostCallback(data.article, data.keywords);
906
999
  handleCloseModal();
907
1000
  };
908
1001
  useLayoutEffect(() => {
@@ -966,7 +1059,6 @@ function ChatWindow({
966
1059
  const handleSourceSelect = (option) => {
967
1060
  var _a2;
968
1061
  const sourceId = (_a2 = option == null ? void 0 : option.value) != null ? _a2 : null;
969
- console.log("Selected source:", option);
970
1062
  setSelectedSource(sourceId);
971
1063
  fetchNews(sourceId);
972
1064
  };
@@ -992,130 +1084,103 @@ function ChatWindow({
992
1084
  document.removeEventListener("mousedown", handleClickOutside);
993
1085
  };
994
1086
  }, [showNewsDropdown]);
995
- function formatAIContent(raw) {
996
- const extracted = extractArticleContent(raw);
997
- if (!extracted || !extracted.article) {
998
- return { blocks: [], metaKeywords: [] };
999
- }
1000
- const { article, metaKeywords } = extracted;
1001
- 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");
1002
- const lines = normalized.split("\n").map((line) => line.replace(/<[^>]+>/g, "").trim()).filter(Boolean);
1003
- const blocks = [];
1004
- lines.forEach((line, index) => {
1005
- if (index === 0 && line.length < 120) {
1006
- blocks.push({ type: "h1", text: line });
1007
- return;
1008
- }
1009
- if (line.length < 90 && !line.endsWith("\u0964") && !line.endsWith(".")) {
1010
- blocks.push({ type: "h2", text: line });
1011
- return;
1012
- }
1013
- blocks.push({ type: "p", text: line });
1014
- });
1015
- return { blocks, metaKeywords };
1016
- }
1017
1087
  return /* @__PURE__ */ jsxs4("div", { className: "cnfy-chat", children: [
1018
1088
  /* @__PURE__ */ jsx5("div", { className: "cnfy-chat-area", children: /* @__PURE__ */ jsxs4("div", { className: "cnfy-chat-scroll", children: [
1019
1089
  messages.map((msg) => {
1020
- var _a2;
1090
+ var _a2, _b2;
1021
1091
  const parsed = formatAIContent(msg.content);
1022
- return /* @__PURE__ */ jsxs4("div", { className: "cnfy-msg", children: [
1023
- /* @__PURE__ */ jsx5("div", { className: "cnfy-msg-avatar-wrap", children: /* @__PURE__ */ jsx5(
1024
- "div",
1092
+ return /* @__PURE__ */ jsx5("div", { className: "cnfy-msg", children: /* @__PURE__ */ jsxs4("div", { className: msg.role === "assistant" ? `cnfy-msg-body` : `cnfy-msg-body you`, children: [
1093
+ msg.role === "assistant" && parsed.isArticle && /* @__PURE__ */ jsx5("div", { className: "cnfy-msg-copy-row", children: /* @__PURE__ */ jsx5(
1094
+ "button",
1025
1095
  {
1026
- className: "cnfy-msg-avatar",
1027
- style: {
1028
- backgroundColor: msg.role === "assistant" ? primaryColor : "#1f2937"
1029
- },
1030
- children: msg.role === "assistant" ? "AI" : "You"
1096
+ onClick: () => handleCopy(parsed, msg.id),
1097
+ className: "cnfy-copy-btn",
1098
+ title: "Copy to clipboard",
1099
+ children: copiedId === msg.id ? /* @__PURE__ */ jsx5(Check, { size: 16, className: "cnfy-copy-icon--copied" }) : /* @__PURE__ */ jsx5(Copy, { size: 16 })
1031
1100
  }
1032
1101
  ) }),
1033
- /* @__PURE__ */ jsxs4("div", { className: "cnfy-msg-body", children: [
1034
- msg.role === "assistant" && parsed.blocks.length > 0 && /* @__PURE__ */ jsx5("div", { className: "cnfy-msg-copy-row", children: /* @__PURE__ */ jsx5(
1035
- "button",
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",
1036
1118
  {
1037
- onClick: () => handleCopy(parsed.blocks, msg.id),
1038
- className: "cnfy-copy-btn",
1039
- title: "Copy to clipboard",
1040
- children: copiedId === msg.id ? /* @__PURE__ */ jsx5(Check, { size: 16, className: "cnfy-copy-icon--copied" }) : /* @__PURE__ */ jsx5(Copy, { size: 16 })
1119
+ className: "cnfy-article-content",
1120
+ dangerouslySetInnerHTML: { __html: parsed.articleHtml }
1041
1121
  }
1042
- ) }),
1043
- parsed.blocks.map((block, idx) => {
1044
- if (block.type === "h1") {
1045
- return /* @__PURE__ */ jsx5(
1046
- "h1",
1047
- {
1048
- className: "cnfy-block-h1",
1049
- children: block.text
1050
- },
1051
- idx
1052
- );
1053
- }
1054
- if (block.type === "h2") {
1055
- return /* @__PURE__ */ jsx5(
1056
- "h2",
1057
- {
1058
- className: "cnfy-block-h2",
1059
- children: block.text
1060
- },
1061
- idx
1062
- );
1063
- }
1064
- return /* @__PURE__ */ jsx5("p", { className: "cnfy-block-p", children: block.text }, idx);
1065
- }),
1066
- parsed.metaKeywords.length > 0 && /* @__PURE__ */ jsx5("div", { className: "cnfy-msg-keywords", children: /* @__PURE__ */ jsx5("div", { className: "cnfy-msg-keywords-list", children: parsed.metaKeywords.map((tag, i) => /* @__PURE__ */ jsxs4(
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(
1067
1135
  "span",
1068
1136
  {
1069
1137
  className: "cnfy-msg-keyword-tag",
1138
+ children: tag
1139
+ },
1140
+ i
1141
+ )) })
1142
+ ] }),
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) => {
1144
+ const IconComponent = ACTION_ICONS[option.id] || FileText;
1145
+ return /* @__PURE__ */ jsxs4(
1146
+ "button",
1147
+ {
1148
+ onClick: () => onSelectAction == null ? void 0 : onSelectAction(option.id, analyzedData.url, analyzedData.content),
1149
+ className: "cnfy-action-btn",
1070
1150
  children: [
1071
- "#",
1072
- tag
1151
+ /* @__PURE__ */ jsx5(IconComponent, { size: 16 }),
1152
+ option.name
1073
1153
  ]
1074
1154
  },
1075
- i
1076
- )) }) }),
1077
- 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) => {
1078
- const IconComponent = ACTION_ICONS[option.id] || FileText;
1079
- return /* @__PURE__ */ jsxs4(
1080
- "button",
1081
- {
1082
- onClick: () => onSelectAction == null ? void 0 : onSelectAction(option.id, analyzedData.url, analyzedData.content),
1083
- className: "cnfy-action-btn",
1084
- children: [
1085
- /* @__PURE__ */ jsx5(IconComponent, { size: 16 }),
1086
- option.name
1087
- ]
1088
- },
1089
- option.id
1090
- );
1091
- }) }),
1092
- msg.role === "assistant" && parsed.blocks.length > 0 && !(analyzedData == null ? void 0 : analyzedData.messageId) && (!isStreaming || msg.id !== ((_a2 = messages[messages.length - 1]) == null ? void 0 : _a2.id)) && /* @__PURE__ */ jsxs4("div", { className: "cnfy-msg-actions", children: [
1093
- /* @__PURE__ */ jsxs4(
1094
- "button",
1095
- {
1096
- onClick: () => handleEdit(parsed.blocks, parsed.metaKeywords, msg.id),
1097
- className: "cnfy-btn-edit",
1098
- children: [
1099
- /* @__PURE__ */ jsx5(Edit3, { size: 16 }),
1100
- "Edit"
1101
- ]
1102
- }
1103
- ),
1104
- /* @__PURE__ */ jsxs4(
1105
- "button",
1106
- {
1107
- onClick: () => handlePost(msg.content, parsed.metaKeywords),
1108
- className: "cnfy-btn-post",
1109
- style: { backgroundColor: primaryColor, color: "#fff" },
1110
- children: [
1111
- /* @__PURE__ */ jsx5(Send, { size: 16 }),
1112
- "Post"
1113
- ]
1114
- }
1115
- )
1116
- ] })
1155
+ option.id
1156
+ );
1157
+ }) }),
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: [
1159
+ /* @__PURE__ */ jsxs4(
1160
+ "button",
1161
+ {
1162
+ onClick: () => handleEdit(parsed, msg.id),
1163
+ className: "cnfy-btn-edit",
1164
+ children: [
1165
+ /* @__PURE__ */ jsx5(Edit3, { size: 16 }),
1166
+ "Edit"
1167
+ ]
1168
+ }
1169
+ ),
1170
+ /* @__PURE__ */ jsxs4(
1171
+ "button",
1172
+ {
1173
+ onClick: () => handlePost({ article: parsed.articleHtml, keywords: parsed.metaKeywords }),
1174
+ className: "cnfy-btn-post",
1175
+ style: { backgroundColor: primaryColor, color: "#fff" },
1176
+ children: [
1177
+ /* @__PURE__ */ jsx5(Send, { size: 16 }),
1178
+ "Post"
1179
+ ]
1180
+ }
1181
+ )
1117
1182
  ] })
1118
- ] }, msg.id);
1183
+ ] }) }, msg.id);
1119
1184
  }),
1120
1185
  /* @__PURE__ */ jsx5("div", { ref: bottomRef })
1121
1186
  ] }) }),
@@ -1247,7 +1312,8 @@ function ChatWindow({
1247
1312
  rows: 1,
1248
1313
  placeholder: "Ask AI something\u2026",
1249
1314
  className: `cnfy-chat-textarea ${!showNewsPanel ? "cnfy-chat-textarea--with-pulse" : ""}`,
1250
- 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
1251
1317
  }
1252
1318
  ),
1253
1319
  /* @__PURE__ */ jsx5(
@@ -1264,11 +1330,14 @@ function ChatWindow({
1264
1330
  EditModal,
1265
1331
  {
1266
1332
  isOpen: editModal.isOpen,
1333
+ initialTitle: editModal.title,
1334
+ initialSubtitle: editModal.subtitle,
1267
1335
  initialContent: editModal.content,
1336
+ initialMetaDescription: editModal.metaDescription,
1268
1337
  metaKeywords: editModal.metaKeywords,
1269
1338
  onClose: handleCloseModal,
1270
- onSaveDraft: handleSaveDraft,
1271
- onPost: handlePost
1339
+ onSaveDraft: (data) => handleSaveDraft({ article: data.article, keywords: data.keywords }),
1340
+ onPost: (data) => handlePost({ article: data.article, keywords: data.keywords })
1272
1341
  }
1273
1342
  )
1274
1343
  ] });
@@ -1355,14 +1424,14 @@ var triggerScrape = async ({
1355
1424
  state,
1356
1425
  cities
1357
1426
  }) => {
1358
- const { data } = await api_default.post("/scrape/trigger", {
1427
+ const { data } = await api_default.post("/chatboat/scrape/trigger", {
1359
1428
  state,
1360
1429
  cities
1361
1430
  });
1362
1431
  return data;
1363
1432
  };
1364
1433
  var getScrapeStatus = async () => {
1365
- const { data } = await api_default.get("/scrape/status");
1434
+ const { data } = await api_default.get("/chatboat/scrape/status");
1366
1435
  return data.data;
1367
1436
  };
1368
1437
 
@@ -1383,8 +1452,17 @@ var ClientSelect = (props) => {
1383
1452
  };
1384
1453
  var ClientSelect_default = ClientSelect;
1385
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
+
1386
1464
  // components/preferences/Preferences.tsx
1387
- 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";
1388
1466
  var STATE_OPTIONS = [
1389
1467
  { value: "Uttar Pradesh", label: "Uttar Pradesh" }
1390
1468
  ];
@@ -1418,23 +1496,6 @@ var LANGUAGE_OPTIONS = [
1418
1496
  { value: "en", label: "English" },
1419
1497
  { value: "hi", label: "Hindi" }
1420
1498
  ];
1421
- var TONE_OPTIONS = [
1422
- { value: "formal", label: "Formal" },
1423
- { value: "casual", label: "Casual" },
1424
- { value: "engaging", label: "Engaging" },
1425
- { value: "professional", label: "Professional" }
1426
- ];
1427
- var STYLE_OPTIONS = [
1428
- { value: "news", label: "News Article" },
1429
- { value: "blog", label: "Blog Post" },
1430
- { value: "editorial", label: "Editorial" },
1431
- { value: "summary", label: "Summary" }
1432
- ];
1433
- var WORD_COUNT_OPTIONS = [
1434
- { value: "short", label: "Short (~300 words)" },
1435
- { value: "medium", label: "Medium (~600 words)" },
1436
- { value: "long", label: "Long (~1000+ words)" }
1437
- ];
1438
1499
  function PreferencesPage() {
1439
1500
  var _a, _b, _c;
1440
1501
  const { preferences, loading, refreshPreferences, updatePreferences } = usePreferences();
@@ -1445,12 +1506,6 @@ function PreferencesPage() {
1445
1506
  const [state, setState] = useState6(null);
1446
1507
  const [cities, setCities] = useState6([]);
1447
1508
  const [language, setLanguage] = useState6(null);
1448
- const [tone, setTone] = useState6(null);
1449
- const [style, setStyle] = useState6(null);
1450
- const [wordCount, setWordCount] = useState6(null);
1451
- const [includeQuotes, setIncludeQuotes] = useState6(true);
1452
- const [includeFAQ, setIncludeFAQ] = useState6(false);
1453
- const [targetAudience, setTargetAudience] = useState6("");
1454
1509
  const [saving, setSaving] = useState6(false);
1455
1510
  const [success, setSuccess] = useState6(false);
1456
1511
  const [scraping, setScraping] = useState6(false);
@@ -1460,13 +1515,7 @@ function PreferencesPage() {
1460
1515
  botName: "",
1461
1516
  state: void 0,
1462
1517
  cities: [],
1463
- language: void 0,
1464
- tone: void 0,
1465
- style: void 0,
1466
- wordCount: void 0,
1467
- includeQuotes: true,
1468
- includeFAQ: false,
1469
- targetAudience: ""
1518
+ language: void 0
1470
1519
  });
1471
1520
  useEffect7(() => {
1472
1521
  const fetchScrapeStatus = async () => {
@@ -1506,7 +1555,7 @@ function PreferencesPage() {
1506
1555
  }
1507
1556
  };
1508
1557
  useEffect7(() => {
1509
- var _a2, _b2, _c2, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1558
+ var _a2, _b2, _c2, _d, _e;
1510
1559
  if (preferences) {
1511
1560
  const name = ((_a2 = preferences.chatbot) == null ? void 0 : _a2.name) || "";
1512
1561
  const pState = (_b2 = preferences.localization) == null ? void 0 : _b2.state;
@@ -1524,38 +1573,11 @@ function PreferencesPage() {
1524
1573
  const langOption = LANGUAGE_OPTIONS.find((opt) => opt.value === pLanguage);
1525
1574
  setLanguage(langOption || null);
1526
1575
  }
1527
- const pTone = (_f = preferences.content) == null ? void 0 : _f.tone;
1528
- const pStyle = (_g = preferences.content) == null ? void 0 : _g.style;
1529
- const pWordCount = (_h = preferences.content) == null ? void 0 : _h.wordCount;
1530
- const pIncludeQuotes = (_j = (_i = preferences.content) == null ? void 0 : _i.includeQuotes) != null ? _j : true;
1531
- const pIncludeFAQ = (_l = (_k = preferences.content) == null ? void 0 : _k.includeFAQ) != null ? _l : false;
1532
- const pTargetAudience = ((_m = preferences.content) == null ? void 0 : _m.targetAudience) || "";
1533
- if (pTone) {
1534
- const toneOption = TONE_OPTIONS.find((opt) => opt.value === pTone);
1535
- setTone(toneOption || null);
1536
- }
1537
- if (pStyle) {
1538
- const styleOption = STYLE_OPTIONS.find((opt) => opt.value === pStyle);
1539
- setStyle(styleOption || null);
1540
- }
1541
- if (pWordCount) {
1542
- const wordCountOption = WORD_COUNT_OPTIONS.find((opt) => opt.value === pWordCount);
1543
- setWordCount(wordCountOption || null);
1544
- }
1545
- setIncludeQuotes(pIncludeQuotes);
1546
- setIncludeFAQ(pIncludeFAQ);
1547
- setTargetAudience(pTargetAudience);
1548
1576
  setOriginalValues({
1549
1577
  botName: name,
1550
1578
  state: pState,
1551
1579
  cities: pCities,
1552
- language: pLanguage,
1553
- tone: pTone,
1554
- style: pStyle,
1555
- wordCount: pWordCount,
1556
- includeQuotes: pIncludeQuotes,
1557
- includeFAQ: pIncludeFAQ,
1558
- targetAudience: pTargetAudience
1580
+ language: pLanguage
1559
1581
  });
1560
1582
  }
1561
1583
  }, [preferences]);
@@ -1587,27 +1609,6 @@ function PreferencesPage() {
1587
1609
  if (currentLanguage !== originalValues.language) {
1588
1610
  payload.language = currentLanguage;
1589
1611
  }
1590
- const currentTone = tone == null ? void 0 : tone.value;
1591
- if (currentTone !== originalValues.tone) {
1592
- payload.tone = currentTone;
1593
- }
1594
- const currentStyle = style == null ? void 0 : style.value;
1595
- if (currentStyle !== originalValues.style) {
1596
- payload.style = currentStyle;
1597
- }
1598
- const currentWordCount = wordCount == null ? void 0 : wordCount.value;
1599
- if (currentWordCount !== originalValues.wordCount) {
1600
- payload.wordCount = currentWordCount;
1601
- }
1602
- if (includeQuotes !== originalValues.includeQuotes) {
1603
- payload.includeQuotes = includeQuotes;
1604
- }
1605
- if (includeFAQ !== originalValues.includeFAQ) {
1606
- payload.includeFAQ = includeFAQ;
1607
- }
1608
- if (targetAudience !== originalValues.targetAudience) {
1609
- payload.targetAudience = targetAudience;
1610
- }
1611
1612
  if (Object.keys(payload).length === 0) {
1612
1613
  toast.error("No changes to save");
1613
1614
  setSaving(false);
@@ -1680,150 +1681,6 @@ function PreferencesPage() {
1680
1681
  ] })
1681
1682
  ] })
1682
1683
  ] }),
1683
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-card", children: [
1684
- /* @__PURE__ */ jsx10("h2", { className: "cnfy-dash-card-title", children: "Localization Settings" }),
1685
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1686
- /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "State" }),
1687
- /* @__PURE__ */ jsx10(
1688
- ClientSelect_default,
1689
- {
1690
- options: STATE_OPTIONS,
1691
- value: state,
1692
- onChange: (option) => setState(option),
1693
- placeholder: "Select state"
1694
- }
1695
- )
1696
- ] }),
1697
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1698
- /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "Cities" }),
1699
- /* @__PURE__ */ jsx10(
1700
- ClientSelect_default,
1701
- {
1702
- isMulti: true,
1703
- options: CITY_OPTIONS,
1704
- value: cities,
1705
- onChange: (options) => setCities(options),
1706
- placeholder: "Select cities",
1707
- isDisabled: !state
1708
- }
1709
- )
1710
- ] }),
1711
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1712
- /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "Language" }),
1713
- /* @__PURE__ */ jsx10(
1714
- ClientSelect_default,
1715
- {
1716
- options: LANGUAGE_OPTIONS,
1717
- value: language,
1718
- onChange: (option) => setLanguage(option),
1719
- placeholder: "Select language"
1720
- }
1721
- )
1722
- ] })
1723
- ] }),
1724
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-card", children: [
1725
- /* @__PURE__ */ jsx10("h2", { className: "cnfy-dash-card-title", children: "Content Generation Settings" }),
1726
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1727
- /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "Tone" }),
1728
- /* @__PURE__ */ jsx10(
1729
- ClientSelect_default,
1730
- {
1731
- options: TONE_OPTIONS,
1732
- value: tone,
1733
- onChange: (option) => setTone(option),
1734
- placeholder: "Select tone"
1735
- }
1736
- ),
1737
- /* @__PURE__ */ jsx10("p", { className: "cnfy-dash-hint", children: "The writing tone for generated content" })
1738
- ] }),
1739
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1740
- /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "Style" }),
1741
- /* @__PURE__ */ jsx10(
1742
- ClientSelect_default,
1743
- {
1744
- options: STYLE_OPTIONS,
1745
- value: style,
1746
- onChange: (option) => setStyle(option),
1747
- placeholder: "Select style"
1748
- }
1749
- ),
1750
- /* @__PURE__ */ jsx10("p", { className: "cnfy-dash-hint", children: "The format/style of generated articles" })
1751
- ] }),
1752
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1753
- /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "Word Count" }),
1754
- /* @__PURE__ */ jsx10(
1755
- ClientSelect_default,
1756
- {
1757
- options: WORD_COUNT_OPTIONS,
1758
- value: wordCount,
1759
- onChange: (option) => setWordCount(option),
1760
- placeholder: "Select word count"
1761
- }
1762
- ),
1763
- /* @__PURE__ */ jsx10("p", { className: "cnfy-dash-hint", children: "Target length for generated content" })
1764
- ] }),
1765
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1766
- /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "Target Audience" }),
1767
- /* @__PURE__ */ jsx10(
1768
- "input",
1769
- {
1770
- value: targetAudience,
1771
- onChange: (e) => setTargetAudience(e.target.value),
1772
- className: "cnfy-dash-input",
1773
- placeholder: "e.g. tech-savvy millennials, business professionals"
1774
- }
1775
- ),
1776
- /* @__PURE__ */ jsx10("p", { className: "cnfy-dash-hint", children: "Describe your target audience for personalized content" })
1777
- ] }),
1778
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-toggle-group", children: [
1779
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-toggle-row", children: [
1780
- /* @__PURE__ */ jsxs7("div", { children: [
1781
- /* @__PURE__ */ jsx10("p", { className: "cnfy-toggle-label", children: "Include Quotes" }),
1782
- /* @__PURE__ */ jsx10("p", { className: "cnfy-toggle-desc", children: "Add relevant quotes to generated articles" })
1783
- ] }),
1784
- /* @__PURE__ */ jsx10(
1785
- "button",
1786
- {
1787
- type: "button",
1788
- role: "switch",
1789
- "aria-checked": includeQuotes,
1790
- onClick: () => setIncludeQuotes(!includeQuotes),
1791
- className: "cnfy-toggle",
1792
- style: { backgroundColor: includeQuotes ? primaryColor : "#d1d5db" },
1793
- children: /* @__PURE__ */ jsx10(
1794
- "span",
1795
- {
1796
- className: `cnfy-toggle-thumb ${includeQuotes ? "cnfy-toggle-thumb--on" : ""}`
1797
- }
1798
- )
1799
- }
1800
- )
1801
- ] }),
1802
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-toggle-row", children: [
1803
- /* @__PURE__ */ jsxs7("div", { children: [
1804
- /* @__PURE__ */ jsx10("p", { className: "cnfy-toggle-label", children: "Include FAQ Section" }),
1805
- /* @__PURE__ */ jsx10("p", { className: "cnfy-toggle-desc", children: "Add FAQ section at the end of articles" })
1806
- ] }),
1807
- /* @__PURE__ */ jsx10(
1808
- "button",
1809
- {
1810
- type: "button",
1811
- role: "switch",
1812
- "aria-checked": includeFAQ,
1813
- onClick: () => setIncludeFAQ(!includeFAQ),
1814
- className: "cnfy-toggle",
1815
- style: { backgroundColor: includeFAQ ? primaryColor : "#d1d5db" },
1816
- children: /* @__PURE__ */ jsx10(
1817
- "span",
1818
- {
1819
- className: `cnfy-toggle-thumb ${includeFAQ ? "cnfy-toggle-thumb--on" : ""}`
1820
- }
1821
- )
1822
- }
1823
- )
1824
- ] })
1825
- ] })
1826
- ] }),
1827
1684
  /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-card", children: [
1828
1685
  /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-card-header", children: [
1829
1686
  /* @__PURE__ */ jsx10("h2", { className: "cnfy-dash-card-title-inline", children: "News Scraping" }),
@@ -1850,7 +1707,7 @@ function PreferencesPage() {
1850
1707
  /* @__PURE__ */ jsxs7("p", { className: "cnfy-dash-info-text", children: [
1851
1708
  "Current configuration: ",
1852
1709
  /* @__PURE__ */ jsx10("strong", { children: (_b = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _b.state }),
1853
- ((_c = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _c.cities) && preferences.localization.cities.length > 0 && /* @__PURE__ */ jsxs7(Fragment, { children: [
1710
+ ((_c = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _c.cities) && preferences.localization.cities.length > 0 && /* @__PURE__ */ jsxs7(Fragment2, { children: [
1854
1711
  " - ",
1855
1712
  preferences.localization.cities.join(", ")
1856
1713
  ] })
@@ -1861,35 +1718,133 @@ function PreferencesPage() {
1861
1718
  onClick: handleScrape,
1862
1719
  disabled: scraping || (scrapeStatus == null ? void 0 : scrapeStatus.isRunning),
1863
1720
  className: "cnfy-dash-btn-save",
1864
- style: { backgroundColor: primaryColor },
1721
+ style: { backgroundColor: hexToRgba(primaryColor, 0.8) },
1865
1722
  children: scraping ? "Starting Scrape..." : (scrapeStatus == null ? void 0 : scrapeStatus.isRunning) ? "Scraping in Progress..." : "Start Scraping"
1866
1723
  }
1867
1724
  )
1868
1725
  ] })
1869
1726
  ] }),
1870
- /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-actions", children: [
1871
- /* @__PURE__ */ jsx10(
1872
- "button",
1873
- {
1874
- onClick: handleSave,
1875
- disabled: saving,
1876
- className: "cnfy-dash-btn-save",
1877
- style: { backgroundColor: primaryColor },
1878
- children: saving ? "Saving..." : "Save Preferences"
1879
- }
1880
- ),
1881
- success && /* @__PURE__ */ jsx10("p", { className: "cnfy-dash-success", style: { color: primaryColor }, children: "Preferences saved successfully \u2705" })
1882
- ] })
1727
+ /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-card", children: [
1728
+ /* @__PURE__ */ jsx10("h2", { className: "cnfy-dash-card-title", children: "Localization Settings" }),
1729
+ /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1730
+ /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "State" }),
1731
+ /* @__PURE__ */ jsx10(
1732
+ ClientSelect_default,
1733
+ {
1734
+ options: STATE_OPTIONS,
1735
+ value: state,
1736
+ onChange: (option) => setState(option),
1737
+ placeholder: "Select state"
1738
+ }
1739
+ )
1740
+ ] }),
1741
+ /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1742
+ /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "Cities" }),
1743
+ /* @__PURE__ */ jsx10(
1744
+ ClientSelect_default,
1745
+ {
1746
+ isMulti: true,
1747
+ options: CITY_OPTIONS,
1748
+ value: cities,
1749
+ onChange: (options) => setCities(options),
1750
+ placeholder: "Select cities",
1751
+ isDisabled: !state
1752
+ }
1753
+ )
1754
+ ] }),
1755
+ /* @__PURE__ */ jsxs7("div", { className: "cnfy-dash-field", children: [
1756
+ /* @__PURE__ */ jsx10("label", { className: "cnfy-dash-label", children: "Language" }),
1757
+ /* @__PURE__ */ jsx10(
1758
+ ClientSelect_default,
1759
+ {
1760
+ options: LANGUAGE_OPTIONS,
1761
+ value: language,
1762
+ onChange: (option) => setLanguage(option),
1763
+ placeholder: "Select language"
1764
+ }
1765
+ )
1766
+ ] })
1767
+ ] }),
1768
+ /* @__PURE__ */ jsx10("div", { className: "cnfy-dash-actions", children: /* @__PURE__ */ jsx10(
1769
+ "button",
1770
+ {
1771
+ onClick: handleSave,
1772
+ disabled: saving,
1773
+ className: "cnfy-dash-btn-save",
1774
+ style: { backgroundColor: primaryColor },
1775
+ children: saving ? "Saving..." : "Save Preferences"
1776
+ }
1777
+ ) })
1883
1778
  ] });
1884
1779
  }
1885
1780
 
1886
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
+ }
1887
1842
  var analyzeInputApi = async (input) => {
1888
- const { data } = await api_default.post("/chat/analyze-input", { input });
1843
+ const { data } = await api_default.post("/chatboat/analyze-input", { input });
1889
1844
  return data.data;
1890
1845
  };
1891
1846
  var createContentApi = async (payload) => {
1892
- const { data } = await api_default.post("/chat/create-content", payload);
1847
+ const { data } = await api_default.post("/chatboat/create-content", payload);
1893
1848
  return data.data;
1894
1849
  };
1895
1850
  var createContentStreamApi = async ({
@@ -1897,22 +1852,18 @@ var createContentStreamApi = async ({
1897
1852
  content,
1898
1853
  actionId,
1899
1854
  settings,
1900
- onChunk,
1855
+ onFieldStart,
1856
+ onContent,
1857
+ onKeywords,
1858
+ onFieldEnd,
1901
1859
  onComplete,
1902
1860
  onError
1903
1861
  }) => {
1904
1862
  var _a;
1905
1863
  const API_BASE_URL = getApiBaseUrl();
1906
- const apiKey = getApiKey();
1907
- const headers = {
1908
- "Content-Type": "application/json"
1909
- };
1910
- if (apiKey) {
1911
- headers["x-api-key"] = apiKey;
1912
- }
1913
1864
  const response = await fetch(`${API_BASE_URL}/chat/create-content/stream`, {
1914
1865
  method: "POST",
1915
- headers,
1866
+ headers: getHeaders(),
1916
1867
  credentials: "include",
1917
1868
  body: JSON.stringify({ url, content, actionId, settings })
1918
1869
  });
@@ -1921,50 +1872,17 @@ var createContentStreamApi = async ({
1921
1872
  throw new Error(`HTTP error! status: ${response.status} - ${errorText}`);
1922
1873
  }
1923
1874
  const reader = (_a = response.body) == null ? void 0 : _a.getReader();
1924
- const decoder = new TextDecoder();
1925
1875
  if (!reader) {
1926
1876
  throw new Error("No reader available");
1927
1877
  }
1928
- let buffer = "";
1929
- let hasReceivedData = false;
1930
- while (true) {
1931
- const { done, value } = await reader.read();
1932
- if (done) {
1933
- if (hasReceivedData) onComplete == null ? void 0 : onComplete();
1934
- break;
1935
- }
1936
- const chunk = decoder.decode(value, { stream: true });
1937
- buffer += chunk;
1938
- const lines = buffer.split("\n");
1939
- buffer = lines.pop() || "";
1940
- for (const line of lines) {
1941
- const trimmedLine = line.trim();
1942
- if (trimmedLine === "") continue;
1943
- hasReceivedData = true;
1944
- if (trimmedLine.startsWith("data: ")) {
1945
- const data = trimmedLine.slice(6).trim();
1946
- if (data === "[DONE]") {
1947
- onComplete == null ? void 0 : onComplete();
1948
- return;
1949
- }
1950
- try {
1951
- const parsed = JSON.parse(data);
1952
- if (parsed.content) onChunk(parsed.content);
1953
- else if (parsed.delta) onChunk(parsed.delta);
1954
- else if (parsed.text) onChunk(parsed.text);
1955
- else if (parsed.chunk) onChunk(parsed.chunk);
1956
- else if (typeof parsed === "string") onChunk(parsed);
1957
- } catch (e) {
1958
- if (data) onChunk(data);
1959
- }
1960
- } else if (trimmedLine) {
1961
- onChunk(trimmedLine + "\n");
1962
- }
1963
- }
1964
- }
1965
- if (!hasReceivedData) {
1966
- throw new Error("No data received from stream");
1967
- }
1878
+ await processSSEStream(reader, {
1879
+ onFieldStart,
1880
+ onContent,
1881
+ onKeywords,
1882
+ onFieldEnd,
1883
+ onComplete,
1884
+ onError
1885
+ });
1968
1886
  };
1969
1887
  var rewriteNewsStreamApi = async ({
1970
1888
  article,
@@ -1976,7 +1894,10 @@ var rewriteNewsStreamApi = async ({
1976
1894
  includeQuotes,
1977
1895
  includeFAQ,
1978
1896
  targetAudience,
1979
- onChunk,
1897
+ onFieldStart,
1898
+ onContent,
1899
+ onKeywords,
1900
+ onFieldEnd,
1980
1901
  onComplete,
1981
1902
  onError
1982
1903
  }) => {
@@ -1985,9 +1906,7 @@ var rewriteNewsStreamApi = async ({
1985
1906
  article,
1986
1907
  language
1987
1908
  };
1988
- if (articleId) {
1989
- payload.articleId = articleId;
1990
- }
1909
+ if (articleId) payload.articleId = articleId;
1991
1910
  if (tone) payload.tone = tone;
1992
1911
  if (style) payload.style = style;
1993
1912
  if (wordCount) payload.wordCount = wordCount;
@@ -1996,102 +1915,42 @@ var rewriteNewsStreamApi = async ({
1996
1915
  if (targetAudience) payload.targetAudience = targetAudience;
1997
1916
  try {
1998
1917
  const API_BASE_URL = getApiBaseUrl();
1999
- const apiKey = getApiKey();
2000
- console.log("\u{1F680} Starting stream request to:", `${API_BASE_URL}/chat/rewrite/stream`);
2001
- console.log("\u{1F4E6} Payload:", payload);
2002
- const headers = {
2003
- "Content-Type": "application/json"
2004
- };
2005
- if (apiKey) {
2006
- headers["x-api-key"] = apiKey;
2007
- }
2008
- const response = await fetch(`${API_BASE_URL}/chat/rewrite/stream`, {
1918
+ const response = await fetch(`${API_BASE_URL}/chatboat/rewrite/stream`, {
2009
1919
  method: "POST",
2010
- headers,
1920
+ headers: getHeaders(),
2011
1921
  credentials: "include",
2012
- // Include cookies for authentication
2013
1922
  body: JSON.stringify(payload)
2014
1923
  });
2015
- console.log("\u{1F4E1} Response status:", response.status);
2016
- console.log("\u{1F4E1} Response headers:", Object.fromEntries(response.headers.entries()));
2017
1924
  if (!response.ok) {
2018
1925
  const errorText = await response.text();
2019
- console.error("\u274C API Error:", response.status, errorText);
2020
1926
  throw new Error(`HTTP error! status: ${response.status} - ${errorText}`);
2021
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
+ }
2022
1941
  const reader = (_a = response.body) == null ? void 0 : _a.getReader();
2023
- const decoder = new TextDecoder();
2024
1942
  if (!reader) {
2025
1943
  throw new Error("No reader available");
2026
1944
  }
2027
- let buffer = "";
2028
- let hasReceivedData = false;
2029
- while (true) {
2030
- const { done, value } = await reader.read();
2031
- if (done) {
2032
- if (hasReceivedData) {
2033
- onComplete == null ? void 0 : onComplete();
2034
- }
2035
- break;
2036
- }
2037
- const chunk = decoder.decode(value, { stream: true });
2038
- buffer += chunk;
2039
- const lines = buffer.split("\n");
2040
- buffer = lines.pop() || "";
2041
- for (const line of lines) {
2042
- const trimmedLine = line.trim();
2043
- if (trimmedLine === "") continue;
2044
- hasReceivedData = true;
2045
- console.log("\u{1F4E8} Received line:", trimmedLine.substring(0, 100) + (trimmedLine.length > 100 ? "..." : ""));
2046
- if (trimmedLine.startsWith("data: ")) {
2047
- const data = trimmedLine.slice(6).trim();
2048
- if (data === "[DONE]") {
2049
- console.log("\u2705 Stream completed with [DONE] signal");
2050
- onComplete == null ? void 0 : onComplete();
2051
- return;
2052
- }
2053
- try {
2054
- const parsed = JSON.parse(data);
2055
- console.log("\u{1F4CB} Parsed JSON:", parsed);
2056
- if (parsed.content) {
2057
- onChunk(parsed.content);
2058
- } else if (parsed.delta) {
2059
- onChunk(parsed.delta);
2060
- } else if (parsed.text) {
2061
- onChunk(parsed.text);
2062
- } else if (parsed.chunk) {
2063
- onChunk(parsed.chunk);
2064
- } else if (typeof parsed === "string") {
2065
- onChunk(parsed);
2066
- } else {
2067
- console.warn("\u26A0\uFE0F Unknown JSON format:", parsed);
2068
- }
2069
- } catch (e) {
2070
- console.log("\u{1F4DD} Non-JSON data, treating as plain text");
2071
- if (data) {
2072
- onChunk(data);
2073
- }
2074
- }
2075
- } else {
2076
- console.log("\u{1F4C4} Plain text chunk");
2077
- if (trimmedLine) {
2078
- onChunk(trimmedLine + "\n");
2079
- }
2080
- }
2081
- }
2082
- }
2083
- if (!hasReceivedData) {
2084
- console.error("\u274C No data received from stream");
2085
- throw new Error("No data received from stream");
2086
- }
2087
- console.log("\u2705 Stream completed successfully");
2088
- } catch (error) {
2089
- console.error("\u274C Streaming error:", error);
2090
- console.error("Error details:", {
2091
- message: error.message,
2092
- name: error.name,
2093
- stack: error.stack
1945
+ await processSSEStream(reader, {
1946
+ onFieldStart,
1947
+ onContent,
1948
+ onKeywords,
1949
+ onFieldEnd,
1950
+ onComplete,
1951
+ onError
2094
1952
  });
1953
+ } catch (error) {
2095
1954
  onError == null ? void 0 : onError(error);
2096
1955
  throw error;
2097
1956
  }
@@ -2111,29 +1970,31 @@ var rewriteNewsApi = async ({
2111
1970
  article,
2112
1971
  language
2113
1972
  };
2114
- if (articleId) {
2115
- payload.articleId = articleId;
2116
- }
1973
+ if (articleId) payload.articleId = articleId;
2117
1974
  if (tone) payload.tone = tone;
2118
1975
  if (style) payload.style = style;
2119
1976
  if (wordCount) payload.wordCount = wordCount;
2120
1977
  if (includeQuotes !== void 0) payload.includeQuotes = includeQuotes;
2121
1978
  if (includeFAQ !== void 0) payload.includeFAQ = includeFAQ;
2122
1979
  if (targetAudience) payload.targetAudience = targetAudience;
2123
- const { data } = await api_default.post("/chat/rewrite", payload);
1980
+ const { data } = await api_default.post("/chatboat/rewrite", payload);
2124
1981
  return data.data;
2125
1982
  };
2126
1983
 
2127
1984
  // components/chatbot/ChatBot.tsx
2128
1985
  import toast2 from "react-hot-toast";
2129
- import { Loader2 } from "lucide-react";
1986
+ import { Loader2 as Loader22 } from "lucide-react";
2130
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
+ }
2131
1991
  function ChatBot({ onPost }) {
2132
1992
  const { loading } = useTheme();
2133
1993
  const { preferences } = usePreferences();
2134
1994
  const [preferencesOpen, setPreferencesOpen] = useState7(false);
2135
1995
  const [messages, setMessages] = useState7([]);
2136
1996
  const [isStreaming, setIsStreaming] = useState7(false);
1997
+ const [activeField, setActiveField] = useState7(null);
2137
1998
  const [analyzedData, setAnalyzedData] = useState7(null);
2138
1999
  const handleRecreate = async ({ title, content, id }) => {
2139
2000
  var _a;
@@ -2144,17 +2005,28 @@ function ChatBot({ onPost }) {
2144
2005
  id: crypto.randomUUID(),
2145
2006
  role: "user",
2146
2007
  content: `Recreate this news:
2147
- ${title}`
2008
+ ${title}`
2148
2009
  },
2149
2010
  {
2150
2011
  id: assistantId,
2151
2012
  role: "assistant",
2152
- content: "\u23F3 Creating article..."
2013
+ content: ""
2153
2014
  }
2154
2015
  ]);
2016
+ setIsStreaming(true);
2155
2017
  try {
2156
- let accumulatedContent = "";
2157
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
+ };
2158
2030
  const contentPrefs = preferences == null ? void 0 : preferences.content;
2159
2031
  const lang = ((_a = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _a.language) === "hi" ? "Hindi" : "English";
2160
2032
  try {
@@ -2168,39 +2040,66 @@ ${title}`
2168
2040
  includeQuotes: contentPrefs == null ? void 0 : contentPrefs.includeQuotes,
2169
2041
  includeFAQ: contentPrefs == null ? void 0 : contentPrefs.includeFAQ,
2170
2042
  targetAudience: contentPrefs == null ? void 0 : contentPrefs.targetAudience,
2171
- onChunk: (chunk) => {
2043
+ onFieldStart: (field) => {
2044
+ setActiveField(field);
2045
+ },
2046
+ onContent: (field, chunk) => {
2172
2047
  hasStartedStreaming = true;
2173
- accumulatedContent += chunk;
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);
2174
2061
  setMessages(
2175
2062
  (prev) => prev.map(
2176
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: accumulatedContent }) : m
2063
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: finalContent }) : m
2177
2064
  )
2178
2065
  );
2179
- },
2180
- onComplete: () => {
2181
- console.log("Streaming completed successfully");
2066
+ setIsStreaming(false);
2067
+ setActiveField(null);
2182
2068
  toast2.success("Article created successfully!");
2183
2069
  },
2184
2070
  onError: async (error) => {
2185
2071
  console.error("Streaming error:", error);
2186
2072
  if (!hasStartedStreaming) {
2187
- console.log("Falling back to regular API...");
2188
2073
  throw error;
2189
2074
  } else {
2075
+ setIsStreaming(false);
2076
+ setActiveField(null);
2190
2077
  toast2.error("Failed to complete article generation");
2191
2078
  setMessages(
2192
2079
  (prev) => prev.map(
2193
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: accumulatedContent || "\u274C Failed to create article. Please try again." }) : m
2080
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: titleBuffer || articleBuffer ? buildStructuredContent(titleBuffer, articleBuffer, keywordsBuffer) : "Failed to create article. Please try again." }) : m
2194
2081
  )
2195
2082
  );
2196
2083
  }
2197
2084
  }
2198
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
+ }
2199
2098
  } catch (streamError) {
2200
2099
  console.log("Streaming failed, using regular API...", streamError);
2201
2100
  setMessages(
2202
2101
  (prev) => prev.map(
2203
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u23F3 Generating with regular API..." }) : m
2102
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "" }) : m
2204
2103
  )
2205
2104
  );
2206
2105
  const result = await rewriteNewsApi({
@@ -2216,17 +2115,20 @@ ${title}`
2216
2115
  });
2217
2116
  setMessages(
2218
2117
  (prev) => prev.map(
2219
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: result.article || result }) : m
2118
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: typeof result === "string" ? result : JSON.stringify(result) }) : m
2220
2119
  )
2221
2120
  );
2121
+ setIsStreaming(false);
2222
2122
  toast2.success("Article created successfully!");
2223
2123
  }
2224
2124
  } catch (err) {
2225
2125
  console.error("Complete Error:", err);
2126
+ setIsStreaming(false);
2127
+ setActiveField(null);
2226
2128
  toast2.error((err == null ? void 0 : err.message) || "An error occurred while creating the article");
2227
2129
  setMessages(
2228
2130
  (prev) => prev.map(
2229
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u274C Failed to create article. Please try again." }) : m
2131
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "Failed to create article. Please try again." }) : m
2230
2132
  )
2231
2133
  );
2232
2134
  }
@@ -2244,9 +2146,10 @@ ${title}`
2244
2146
  if (hasUrl) {
2245
2147
  setMessages((prev) => [
2246
2148
  ...prev,
2247
- { id: assistantId, role: "assistant", content: "\u{1F50D} Analyzing your link..." }
2149
+ { id: assistantId, role: "assistant", content: "Analyzing your link..." }
2248
2150
  ]);
2249
2151
  try {
2152
+ return;
2250
2153
  const result = await analyzeInputApi(text);
2251
2154
  if (result.hasUrl && ((_a = result.options) == null ? void 0 : _a.length) > 0) {
2252
2155
  setAnalyzedData({
@@ -2277,20 +2180,30 @@ ${optionsList}`
2277
2180
  toast2.error("Failed to analyze the link");
2278
2181
  setMessages(
2279
2182
  (prev) => prev.map(
2280
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u274C Failed to analyze the link. Please try again." }) : m
2183
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "Failed to analyze the link. Please try again." }) : m
2281
2184
  )
2282
2185
  );
2283
2186
  }
2284
2187
  } else {
2285
2188
  setMessages((prev) => [
2286
2189
  ...prev,
2287
- { id: assistantId, role: "assistant", content: "\u23F3 Generating content..." }
2190
+ { id: assistantId, role: "assistant", content: "" }
2288
2191
  ]);
2289
2192
  setIsStreaming(true);
2290
2193
  try {
2291
2194
  const contentPrefs = preferences == null ? void 0 : preferences.content;
2292
2195
  const lang = ((_b = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _b.language) === "hi" ? "Hindi" : "English";
2293
- let accumulatedContent = "";
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
+ };
2294
2207
  await rewriteNewsStreamApi({
2295
2208
  article: text,
2296
2209
  language: lang,
@@ -2300,30 +2213,58 @@ ${optionsList}`
2300
2213
  includeQuotes: contentPrefs == null ? void 0 : contentPrefs.includeQuotes,
2301
2214
  includeFAQ: contentPrefs == null ? void 0 : contentPrefs.includeFAQ,
2302
2215
  targetAudience: contentPrefs == null ? void 0 : contentPrefs.targetAudience,
2303
- onChunk: (chunk) => {
2304
- accumulatedContent += chunk;
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);
2305
2233
  setMessages(
2306
2234
  (prev) => prev.map(
2307
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: accumulatedContent }) : m
2235
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: finalContent }) : m
2308
2236
  )
2309
2237
  );
2310
- },
2311
- onComplete: () => {
2312
2238
  setIsStreaming(false);
2239
+ setActiveField(null);
2313
2240
  toast2.success("Content generated!");
2314
2241
  },
2315
2242
  onError: (error) => {
2316
2243
  console.error("Stream error:", error);
2317
2244
  setIsStreaming(false);
2245
+ setActiveField(null);
2318
2246
  toast2.error("Failed to generate content");
2319
2247
  }
2320
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
+ }
2321
2261
  } catch (err) {
2322
2262
  console.error("Send message error:", err);
2323
2263
  setIsStreaming(false);
2264
+ setActiveField(null);
2324
2265
  setMessages(
2325
2266
  (prev) => prev.map(
2326
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u274C Failed to generate content. Please try again." }) : m
2267
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "Failed to generate content. Please try again." }) : m
2327
2268
  )
2328
2269
  );
2329
2270
  }
@@ -2337,12 +2278,22 @@ ${optionsList}`
2337
2278
  setMessages((prev) => [
2338
2279
  ...prev,
2339
2280
  { id: crypto.randomUUID(), role: "user", content: `Action: ${actionName}` },
2340
- { id: assistantId, role: "assistant", content: "\u23F3 Creating content..." }
2281
+ { id: assistantId, role: "assistant", content: "" }
2341
2282
  ]);
2342
2283
  setIsStreaming(true);
2343
2284
  try {
2344
2285
  const contentPrefs = preferences == null ? void 0 : preferences.content;
2345
- let accumulatedContent = "";
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
+ };
2346
2297
  try {
2347
2298
  await createContentStreamApi({
2348
2299
  url,
@@ -2353,24 +2304,51 @@ ${optionsList}`
2353
2304
  style: contentPrefs == null ? void 0 : contentPrefs.style,
2354
2305
  wordCount: contentPrefs == null ? void 0 : contentPrefs.wordCount
2355
2306
  },
2356
- onChunk: (chunk) => {
2357
- accumulatedContent += chunk;
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);
2358
2324
  setMessages(
2359
2325
  (prev) => prev.map(
2360
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: accumulatedContent }) : m
2326
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: finalContent }) : m
2361
2327
  )
2362
2328
  );
2363
- },
2364
- onComplete: () => {
2365
2329
  setIsStreaming(false);
2330
+ setActiveField(null);
2366
2331
  toast2.success("Content created!");
2367
2332
  },
2368
2333
  onError: (error) => {
2369
2334
  console.error("Stream error:", error);
2370
2335
  setIsStreaming(false);
2336
+ setActiveField(null);
2371
2337
  toast2.error("Failed to create content");
2372
2338
  }
2373
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
+ }
2374
2352
  } catch (e) {
2375
2353
  const result = await createContentApi({ url, content, actionId, settings: {
2376
2354
  tone: contentPrefs == null ? void 0 : contentPrefs.tone,
@@ -2379,25 +2357,27 @@ ${optionsList}`
2379
2357
  } });
2380
2358
  setMessages(
2381
2359
  (prev) => prev.map(
2382
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: result.article || result.content || JSON.stringify(result) }) : m
2360
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: typeof result === "string" ? result : JSON.stringify(result) }) : m
2383
2361
  )
2384
2362
  );
2385
2363
  setIsStreaming(false);
2364
+ setActiveField(null);
2386
2365
  toast2.success("Content created!");
2387
2366
  }
2388
2367
  } catch (err) {
2389
2368
  console.error("Create content error:", err);
2390
2369
  setIsStreaming(false);
2370
+ setActiveField(null);
2391
2371
  setMessages(
2392
2372
  (prev) => prev.map(
2393
- (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u274C Failed to create content. Please try again." }) : m
2373
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "Failed to create content. Please try again." }) : m
2394
2374
  )
2395
2375
  );
2396
2376
  }
2397
2377
  };
2398
2378
  if (loading) {
2399
2379
  return /* @__PURE__ */ jsx11("div", { className: "cnfy-loading", children: /* @__PURE__ */ jsxs8("div", { className: "cnfy-loading-inner", children: [
2400
- /* @__PURE__ */ jsx11(Loader2, { className: "cnfy-loading-spinner cnfy-animate-spin" }),
2380
+ /* @__PURE__ */ jsx11(Loader22, { className: "cnfy-loading-spinner cnfy-animate-spin" }),
2401
2381
  /* @__PURE__ */ jsx11("p", { className: "cnfy-loading-text", children: "Loading..." })
2402
2382
  ] }) });
2403
2383
  }
@@ -2411,6 +2391,7 @@ ${optionsList}`
2411
2391
  onSend: handleSendMessage,
2412
2392
  onSelectNews: handleRecreate,
2413
2393
  isStreaming,
2394
+ activeField,
2414
2395
  analyzedData,
2415
2396
  onSelectAction: handleSelectAction,
2416
2397
  onPost