thikanaa 0.1.2 → 0.1.3
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.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -14,7 +14,9 @@ interface ChatPopupProps {
|
|
|
14
14
|
messages?: Message[];
|
|
15
15
|
onMessageSend?: (message: Message) => void;
|
|
16
16
|
onResponseReceive?: (response: string) => void;
|
|
17
|
+
mockMode?: boolean;
|
|
18
|
+
position?: "fixed" | "relative";
|
|
17
19
|
}
|
|
18
|
-
declare const ChatPopup: ({ systemPrompt, portfolioData: externalPortfolioData, apiUrl, assistantName, initialMessage, model, messages: externalMessages, onMessageSend, onResponseReceive, }: ChatPopupProps) => react_jsx_runtime.JSX.Element;
|
|
20
|
+
declare const ChatPopup: ({ systemPrompt, portfolioData: externalPortfolioData, apiUrl, assistantName, initialMessage, model, messages: externalMessages, onMessageSend, onResponseReceive, mockMode, position, }: ChatPopupProps) => react_jsx_runtime.JSX.Element;
|
|
19
21
|
|
|
20
22
|
export { ChatPopup, type ChatPopupProps };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,9 @@ interface ChatPopupProps {
|
|
|
14
14
|
messages?: Message[];
|
|
15
15
|
onMessageSend?: (message: Message) => void;
|
|
16
16
|
onResponseReceive?: (response: string) => void;
|
|
17
|
+
mockMode?: boolean;
|
|
18
|
+
position?: "fixed" | "relative";
|
|
17
19
|
}
|
|
18
|
-
declare const ChatPopup: ({ systemPrompt, portfolioData: externalPortfolioData, apiUrl, assistantName, initialMessage, model, messages: externalMessages, onMessageSend, onResponseReceive, }: ChatPopupProps) => react_jsx_runtime.JSX.Element;
|
|
20
|
+
declare const ChatPopup: ({ systemPrompt, portfolioData: externalPortfolioData, apiUrl, assistantName, initialMessage, model, messages: externalMessages, onMessageSend, onResponseReceive, mockMode, position, }: ChatPopupProps) => react_jsx_runtime.JSX.Element;
|
|
19
21
|
|
|
20
22
|
export { ChatPopup, type ChatPopupProps };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var I=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var K=(l,n)=>{for(var g in n)I(l,g,{get:n[g],enumerable:!0})},U=(l,n,g,u)=>{if(n&&typeof n=="object"||typeof n=="function")for(let d of q(n))!F.call(l,d)&&d!==g&&I(l,d,{get:()=>n[d],enumerable:!(u=W(n,d))||u.enumerable});return l};var G=l=>U(I({},"__esModule",{value:!0}),l);var X={};K(X,{ChatPopup:()=>V});module.exports=G(X);var t=require("react");var s=require("react/jsx-runtime"),V=({systemPrompt:l,portfolioData:n,apiUrl:g="/chatbot",assistantName:u="Thikana",initialMessage:d,model:C,messages:p,onMessageSend:D,onResponseReceive:x,mockMode:H=!1,position:j="relative"})=>{let[h,E]=(0,t.useState)(""),[b,f]=(0,t.useState)([]),[w,L]=(0,t.useState)(!1),[R,$]=(0,t.useState)(null),[P,N]=(0,t.useState)({width:330,height:480}),[y,T]=(0,t.useState)(!1),v=(0,t.useRef)(null),m=(0,t.useRef)(null),z=(0,t.useRef)(null),k=p||b,O=n||R;(0,t.useEffect)(()=>{if((!p||p.length===0)&&b.length===0){let e=localStorage.getItem("messages");f(e?JSON.parse(e):[{role:"assistant",content:d||`Hi this is ${u}! How can I help you today?`}])}},[p,d,u,b.length]),(0,t.useEffect)(()=>{n||(async()=>{try{let r=await(await fetch("https://raw.githubusercontent.com/hi-malay/portfolio-data/refs/heads/main/scrapped_data.json")).json();$(r)}catch(o){console.error("Error fetching portfolio data:",o)}})()},[n]);let A=()=>{z.current?.scrollIntoView({behavior:"smooth"})};(0,t.useEffect)(()=>{A()},[k]);let B=async e=>{if(H){await new Promise(a=>setTimeout(a,1e3));let i=["That's an interesting question! Let me help you with that.","I understand what you're asking. Here's what I think...","Great question! Based on what you've told me, I'd suggest...","Let me break that down for you.","I'm here to help! Here's my take on that..."],c=i[Math.floor(Math.random()*i.length)];return x&&x(c),c}let o=await fetch(g,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messages:e,portfolioData:O,systemPrompt:l,model:C})});if(!o.ok){let i=await o.json();throw new Error(i.error||"Failed to get AI response")}let r=await o.json();return x&&x(r.text),r.text},S=async e=>{if(!e.trim()||w)return;let o={role:"user",content:e};D&&D(o);let r=[...k,o];p||f(r),E(""),L(!0);try{let c={role:"assistant",content:await B(r)},a=[...r,c];p||(f(a),localStorage.setItem("messages",JSON.stringify(a)))}catch(i){console.error("Error calling AI:",i);let c={role:"assistant",content:"Sorry, I encountered an error. Please try again later."},a=[...r,c];p||(f(a),localStorage.setItem("messages",JSON.stringify(a)))}finally{L(!1)}};(0,t.useEffect)(()=>{m.current&&(m.current.style.height="auto",m.current.style.height=`${Math.min(m.current.scrollHeight,100)}px`)},[h]);let J=(0,t.useCallback)(e=>{e.preventDefault(),T(!0)},[]);return(0,t.useEffect)(()=>{if(!y)return;let e=r=>{if(!v.current)return;let i=v.current.getBoundingClientRect(),c=i.right-r.clientX,a=i.bottom-r.clientY;c>250&&c<800&&N(M=>({...M,width:c})),a>300&&a<800&&N(M=>({...M,height:a}))},o=()=>{T(!1)};return window.addEventListener("mousemove",e),window.addEventListener("mouseup",o),()=>{window.removeEventListener("mousemove",e),window.removeEventListener("mouseup",o)}},[y]),(0,s.jsxs)("div",{ref:v,className:`chat-popup-wrapper ${y?"resizing":""}`,style:{width:`${P.width}px`,height:`${P.height}px`,position:j},children:[(0,s.jsx)("div",{className:"stretch-icon",onMouseDown:J}),(0,s.jsxs)("div",{className:"messages-container",children:[k.map((e,o)=>(0,s.jsx)("div",{className:`message ${e.role==="user"?"user":"ai"}`,children:e.content},o)),w&&(0,s.jsx)("div",{className:"message ai loading",children:"Thinking..."}),(0,s.jsx)("div",{ref:z})]}),(0,s.jsxs)("div",{className:"input-container",children:[(0,s.jsx)("textarea",{ref:m,rows:1,placeholder:"What's on your mind?",value:h,onKeyDown:e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),S(h))},onChange:e=>E(e.target.value)}),(0,s.jsx)("button",{onClick:()=>S(h),disabled:!h.trim()||w,className:"send-button",children:(0,s.jsxs)("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,s.jsx)("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),(0,s.jsx)("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})})]})]})};0&&(module.exports={ChatPopup});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/chat-popup.tsx"],"sourcesContent":["export * from \"./components/chat-popup\";\n","import React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport \"./chat-popup.css\";\n\ntype Message = {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n};\n\nexport interface ChatPopupProps {\n systemPrompt?: string;\n portfolioData?: any;\n apiUrl?: string;\n assistantName?: string;\n initialMessage?: string;\n model?: string;\n messages?: Message[];\n onMessageSend?: (message: Message) => void;\n onResponseReceive?: (response: string) => void;\n}\n\nexport const ChatPopup = ({\n systemPrompt,\n portfolioData: externalPortfolioData,\n apiUrl = \"/chatbot\",\n assistantName = \"Thikana\",\n initialMessage,\n model,\n messages: externalMessages,\n onMessageSend,\n onResponseReceive,\n}: ChatPopupProps) => {\n const [input, setInput] = useState<string>(\"\");\n const [internalMessages, setInternalMessages] = useState<Message[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [internalPortfolioData, setInternalPortfolioData] = useState<any>(null);\n const [dimensions, setDimensions] = useState({ width: 330, height: 480 });\n const [isResizing, setIsResizing] = useState(false);\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n const activeMessages = externalMessages || internalMessages;\n const activePortfolioData = externalPortfolioData || internalPortfolioData;\n\n useEffect(() => {\n if (!externalMessages || externalMessages.length === 0) {\n if (internalMessages.length === 0) {\n const saved = localStorage.getItem(\"messages\");\n if (saved) {\n setInternalMessages(JSON.parse(saved));\n } else {\n setInternalMessages([\n {\n role: \"assistant\",\n content:\n initialMessage ||\n `Hi this is ${assistantName}! How can I help you today?`,\n },\n ]);\n }\n }\n }\n }, [\n externalMessages,\n initialMessage,\n assistantName,\n internalMessages.length,\n ]);\n\n useEffect(() => {\n if (!externalPortfolioData) {\n const fetchPortfolioData = async () => {\n try {\n const response = await fetch(\n \"https://raw.githubusercontent.com/hi-malay/portfolio-data/refs/heads/main/scrapped_data.json\",\n );\n const data = await response.json();\n setInternalPortfolioData(data);\n } catch (error) {\n console.error(\"Error fetching portfolio data:\", error);\n }\n };\n fetchPortfolioData();\n }\n }, [externalPortfolioData]);\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [activeMessages]);\n\n const getAIResponse = async (currentMessages: Message[]): Promise<string> => {\n const response = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n messages: currentMessages,\n portfolioData: activePortfolioData,\n systemPrompt,\n model,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || \"Failed to get AI response\");\n }\n\n const data = await response.json();\n if (onResponseReceive) onResponseReceive(data.text);\n return data.text;\n };\n\n const callModel = async (userInput: string) => {\n if (!userInput.trim() || isLoading) return;\n\n const userMessage: Message = { role: \"user\", content: userInput };\n if (onMessageSend) onMessageSend(userMessage);\n\n const newMessages = [...activeMessages, userMessage];\n\n if (!externalMessages) {\n setInternalMessages(newMessages);\n }\n\n setInput(\"\");\n setIsLoading(true);\n\n try {\n const text = await getAIResponse(newMessages);\n\n const assistantMessage: Message = {\n role: \"assistant\",\n content: text,\n };\n\n const updatedMessages = [...newMessages, assistantMessage];\n if (!externalMessages) {\n setInternalMessages(updatedMessages);\n localStorage.setItem(\"messages\", JSON.stringify(updatedMessages));\n }\n } catch (error) {\n console.error(\"Error calling AI:\", error);\n const defaultFailMessage: Message = {\n role: \"assistant\",\n content: \"Sorry, I encountered an error. Please try again later.\",\n };\n const updatedMessages = [...newMessages, defaultFailMessage];\n if (!externalMessages) {\n setInternalMessages(updatedMessages);\n localStorage.setItem(\"messages\", JSON.stringify(updatedMessages));\n }\n } finally {\n setIsLoading(false);\n }\n };\n\n useEffect(() => {\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 100)}px`;\n }\n }, [input]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n setIsResizing(true);\n }, []);\n\n useEffect(() => {\n if (!isResizing) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n if (!wrapperRef.current) return;\n\n const rect = wrapperRef.current.getBoundingClientRect();\n const newWidth = rect.right - e.clientX;\n const newHeight = rect.bottom - e.clientY;\n\n if (newWidth > 250 && newWidth < 800) {\n setDimensions((prev) => ({ ...prev, width: newWidth }));\n }\n if (newHeight > 300 && newHeight < 800) {\n setDimensions((prev) => ({ ...prev, height: newHeight }));\n }\n };\n\n const handleMouseUp = () => {\n setIsResizing(false);\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [isResizing]);\n\n return (\n <div\n ref={wrapperRef}\n className={`chat-popup-wrapper ${isResizing ? \"resizing\" : \"\"}`}\n style={{\n width: `${dimensions.width}px`,\n height: `${dimensions.height}px`,\n }}\n >\n <div className=\"stretch-icon\" onMouseDown={handleMouseDown}></div>\n <div className=\"messages-container\">\n {activeMessages.map((msg: Message, index: number) => (\n <div\n key={index}\n className={`message ${msg.role === \"user\" ? \"user\" : \"ai\"}`}\n >\n {msg.content}\n </div>\n ))}\n {isLoading && <div className=\"message ai loading\">Thinking...</div>}\n <div ref={messagesEndRef} />\n </div>\n\n <div className=\"input-container\">\n <textarea\n ref={textareaRef}\n rows={1}\n placeholder=\"What's on your mind?\"\n value={input}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n callModel(input);\n }\n }}\n onChange={(e) => setInput(e.target.value)}\n />\n <button\n onClick={() => callModel(input)}\n disabled={!input.trim() || isLoading}\n className=\"send-button\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["index_exports","__export","ChatPopup","__toCommonJS","import_react","import_jsx_runtime","ChatPopup","systemPrompt","externalPortfolioData","apiUrl","assistantName","initialMessage","model","externalMessages","onMessageSend","onResponseReceive","input","setInput","internalMessages","setInternalMessages","isLoading","setIsLoading","internalPortfolioData","setInternalPortfolioData","dimensions","setDimensions","isResizing","setIsResizing","wrapperRef","textareaRef","messagesEndRef","activeMessages","activePortfolioData","saved","data","error","scrollToBottom","getAIResponse","currentMessages","response","errorData","callModel","userInput","userMessage","newMessages","assistantMessage","updatedMessages","defaultFailMessage","handleMouseDown","handleMouseMove","e","rect","newWidth","newHeight","prev","handleMouseUp","msg","index"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/chat-popup.tsx"],"sourcesContent":["export * from \"./components/chat-popup\";\n","import React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport \"./chat-popup.css\";\n\ntype Message = {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n};\n\nexport interface ChatPopupProps {\n systemPrompt?: string;\n portfolioData?: any;\n apiUrl?: string;\n assistantName?: string;\n initialMessage?: string;\n model?: string;\n messages?: Message[];\n onMessageSend?: (message: Message) => void;\n onResponseReceive?: (response: string) => void;\n mockMode?: boolean; // If true, uses mock responses instead of API calls\n position?: \"fixed\" | \"relative\"; // Position style for the wrapper\n}\n\nexport const ChatPopup = ({\n systemPrompt,\n portfolioData: externalPortfolioData,\n apiUrl = \"/chatbot\",\n assistantName = \"Thikana\",\n initialMessage,\n model,\n messages: externalMessages,\n onMessageSend,\n onResponseReceive,\n mockMode = false,\n position = \"relative\",\n}: ChatPopupProps) => {\n const [input, setInput] = useState<string>(\"\");\n const [internalMessages, setInternalMessages] = useState<Message[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [internalPortfolioData, setInternalPortfolioData] = useState<any>(null);\n const [dimensions, setDimensions] = useState({ width: 330, height: 480 });\n const [isResizing, setIsResizing] = useState(false);\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n const activeMessages = externalMessages || internalMessages;\n const activePortfolioData = externalPortfolioData || internalPortfolioData;\n\n useEffect(() => {\n if (!externalMessages || externalMessages.length === 0) {\n if (internalMessages.length === 0) {\n const saved = localStorage.getItem(\"messages\");\n if (saved) {\n setInternalMessages(JSON.parse(saved));\n } else {\n setInternalMessages([\n {\n role: \"assistant\",\n content:\n initialMessage ||\n `Hi this is ${assistantName}! How can I help you today?`,\n },\n ]);\n }\n }\n }\n }, [\n externalMessages,\n initialMessage,\n assistantName,\n internalMessages.length,\n ]);\n\n useEffect(() => {\n if (!externalPortfolioData) {\n const fetchPortfolioData = async () => {\n try {\n const response = await fetch(\n \"https://raw.githubusercontent.com/hi-malay/portfolio-data/refs/heads/main/scrapped_data.json\",\n );\n const data = await response.json();\n setInternalPortfolioData(data);\n } catch (error) {\n console.error(\"Error fetching portfolio data:\", error);\n }\n };\n fetchPortfolioData();\n }\n }, [externalPortfolioData]);\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [activeMessages]);\n\n const getAIResponse = async (currentMessages: Message[]): Promise<string> => {\n // Mock mode for testing without API\n if (mockMode) {\n await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate API delay\n const mockResponses = [\n \"That's an interesting question! Let me help you with that.\",\n \"I understand what you're asking. Here's what I think...\",\n \"Great question! Based on what you've told me, I'd suggest...\",\n \"Let me break that down for you.\",\n \"I'm here to help! Here's my take on that...\",\n ];\n const response =\n mockResponses[Math.floor(Math.random() * mockResponses.length)];\n if (onResponseReceive) onResponseReceive(response);\n return response;\n }\n\n const response = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n messages: currentMessages,\n portfolioData: activePortfolioData,\n systemPrompt,\n model,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || \"Failed to get AI response\");\n }\n\n const data = await response.json();\n if (onResponseReceive) onResponseReceive(data.text);\n return data.text;\n };\n\n const callModel = async (userInput: string) => {\n if (!userInput.trim() || isLoading) return;\n\n const userMessage: Message = { role: \"user\", content: userInput };\n if (onMessageSend) onMessageSend(userMessage);\n\n const newMessages = [...activeMessages, userMessage];\n\n if (!externalMessages) {\n setInternalMessages(newMessages);\n }\n\n setInput(\"\");\n setIsLoading(true);\n\n try {\n const text = await getAIResponse(newMessages);\n\n const assistantMessage: Message = {\n role: \"assistant\",\n content: text,\n };\n\n const updatedMessages = [...newMessages, assistantMessage];\n if (!externalMessages) {\n setInternalMessages(updatedMessages);\n localStorage.setItem(\"messages\", JSON.stringify(updatedMessages));\n }\n } catch (error) {\n console.error(\"Error calling AI:\", error);\n const defaultFailMessage: Message = {\n role: \"assistant\",\n content: \"Sorry, I encountered an error. Please try again later.\",\n };\n const updatedMessages = [...newMessages, defaultFailMessage];\n if (!externalMessages) {\n setInternalMessages(updatedMessages);\n localStorage.setItem(\"messages\", JSON.stringify(updatedMessages));\n }\n } finally {\n setIsLoading(false);\n }\n };\n\n useEffect(() => {\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 100)}px`;\n }\n }, [input]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n setIsResizing(true);\n }, []);\n\n useEffect(() => {\n if (!isResizing) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n if (!wrapperRef.current) return;\n\n const rect = wrapperRef.current.getBoundingClientRect();\n const newWidth = rect.right - e.clientX;\n const newHeight = rect.bottom - e.clientY;\n\n if (newWidth > 250 && newWidth < 800) {\n setDimensions((prev) => ({ ...prev, width: newWidth }));\n }\n if (newHeight > 300 && newHeight < 800) {\n setDimensions((prev) => ({ ...prev, height: newHeight }));\n }\n };\n\n const handleMouseUp = () => {\n setIsResizing(false);\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [isResizing]);\n\n return (\n <div\n ref={wrapperRef}\n className={`chat-popup-wrapper ${isResizing ? \"resizing\" : \"\"}`}\n style={{\n width: `${dimensions.width}px`,\n height: `${dimensions.height}px`,\n position: position,\n }}\n >\n <div className=\"stretch-icon\" onMouseDown={handleMouseDown}></div>\n <div className=\"messages-container\">\n {activeMessages.map((msg: Message, index: number) => (\n <div\n key={index}\n className={`message ${msg.role === \"user\" ? \"user\" : \"ai\"}`}\n >\n {msg.content}\n </div>\n ))}\n {isLoading && <div className=\"message ai loading\">Thinking...</div>}\n <div ref={messagesEndRef} />\n </div>\n\n <div className=\"input-container\">\n <textarea\n ref={textareaRef}\n rows={1}\n placeholder=\"What's on your mind?\"\n value={input}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n callModel(input);\n }\n }}\n onChange={(e) => setInput(e.target.value)}\n />\n <button\n onClick={() => callModel(input)}\n disabled={!input.trim() || isLoading}\n className=\"send-button\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["index_exports","__export","ChatPopup","__toCommonJS","import_react","import_jsx_runtime","ChatPopup","systemPrompt","externalPortfolioData","apiUrl","assistantName","initialMessage","model","externalMessages","onMessageSend","onResponseReceive","mockMode","position","input","setInput","internalMessages","setInternalMessages","isLoading","setIsLoading","internalPortfolioData","setInternalPortfolioData","dimensions","setDimensions","isResizing","setIsResizing","wrapperRef","textareaRef","messagesEndRef","activeMessages","activePortfolioData","saved","data","error","scrollToBottom","getAIResponse","currentMessages","resolve","mockResponses","response","errorData","callModel","userInput","userMessage","newMessages","assistantMessage","updatedMessages","defaultFailMessage","handleMouseDown","handleMouseMove","e","rect","newWidth","newHeight","prev","handleMouseUp","msg","index"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useState as c,useRef as
|
|
1
|
+
import{useState as c,useRef as k,useEffect as g,useCallback as F}from"react";import{jsx as a,jsxs as h}from"react/jsx-runtime";var Y=({systemPrompt:C,portfolioData:f,apiUrl:H="/chatbot",assistantName:M="Thikana",initialMessage:I,model:j,messages:i,onMessageSend:D,onResponseReceive:u,mockMode:R=!1,position:$="relative"})=>{let[l,E]=c(""),[m,d]=c([]),[x,L]=c(!1),[O,A]=c(null),[P,N]=c({width:330,height:480}),[b,T]=c(!1),w=k(null),p=k(null),z=k(null),y=i||m,B=f||O;g(()=>{if((!i||i.length===0)&&m.length===0){let e=localStorage.getItem("messages");d(e?JSON.parse(e):[{role:"assistant",content:I||`Hi this is ${M}! How can I help you today?`}])}},[i,I,M,m.length]),g(()=>{f||(async()=>{try{let o=await(await fetch("https://raw.githubusercontent.com/hi-malay/portfolio-data/refs/heads/main/scrapped_data.json")).json();A(o)}catch(t){console.error("Error fetching portfolio data:",t)}})()},[f]);let J=()=>{z.current?.scrollIntoView({behavior:"smooth"})};g(()=>{J()},[y]);let W=async e=>{if(R){await new Promise(s=>setTimeout(s,1e3));let n=["That's an interesting question! Let me help you with that.","I understand what you're asking. Here's what I think...","Great question! Based on what you've told me, I'd suggest...","Let me break that down for you.","I'm here to help! Here's my take on that..."],r=n[Math.floor(Math.random()*n.length)];return u&&u(r),r}let t=await fetch(H,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messages:e,portfolioData:B,systemPrompt:C,model:j})});if(!t.ok){let n=await t.json();throw new Error(n.error||"Failed to get AI response")}let o=await t.json();return u&&u(o.text),o.text},S=async e=>{if(!e.trim()||x)return;let t={role:"user",content:e};D&&D(t);let o=[...y,t];i||d(o),E(""),L(!0);try{let r={role:"assistant",content:await W(o)},s=[...o,r];i||(d(s),localStorage.setItem("messages",JSON.stringify(s)))}catch(n){console.error("Error calling AI:",n);let r={role:"assistant",content:"Sorry, I encountered an error. Please try again later."},s=[...o,r];i||(d(s),localStorage.setItem("messages",JSON.stringify(s)))}finally{L(!1)}};g(()=>{p.current&&(p.current.style.height="auto",p.current.style.height=`${Math.min(p.current.scrollHeight,100)}px`)},[l]);let q=F(e=>{e.preventDefault(),T(!0)},[]);return g(()=>{if(!b)return;let e=o=>{if(!w.current)return;let n=w.current.getBoundingClientRect(),r=n.right-o.clientX,s=n.bottom-o.clientY;r>250&&r<800&&N(v=>({...v,width:r})),s>300&&s<800&&N(v=>({...v,height:s}))},t=()=>{T(!1)};return window.addEventListener("mousemove",e),window.addEventListener("mouseup",t),()=>{window.removeEventListener("mousemove",e),window.removeEventListener("mouseup",t)}},[b]),h("div",{ref:w,className:`chat-popup-wrapper ${b?"resizing":""}`,style:{width:`${P.width}px`,height:`${P.height}px`,position:$},children:[a("div",{className:"stretch-icon",onMouseDown:q}),h("div",{className:"messages-container",children:[y.map((e,t)=>a("div",{className:`message ${e.role==="user"?"user":"ai"}`,children:e.content},t)),x&&a("div",{className:"message ai loading",children:"Thinking..."}),a("div",{ref:z})]}),h("div",{className:"input-container",children:[a("textarea",{ref:p,rows:1,placeholder:"What's on your mind?",value:l,onKeyDown:e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),S(l))},onChange:e=>E(e.target.value)}),a("button",{onClick:()=>S(l),disabled:!l.trim()||x,className:"send-button",children:h("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[a("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),a("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})})]})]})};export{Y as ChatPopup};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/chat-popup.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport \"./chat-popup.css\";\n\ntype Message = {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n};\n\nexport interface ChatPopupProps {\n systemPrompt?: string;\n portfolioData?: any;\n apiUrl?: string;\n assistantName?: string;\n initialMessage?: string;\n model?: string;\n messages?: Message[];\n onMessageSend?: (message: Message) => void;\n onResponseReceive?: (response: string) => void;\n}\n\nexport const ChatPopup = ({\n systemPrompt,\n portfolioData: externalPortfolioData,\n apiUrl = \"/chatbot\",\n assistantName = \"Thikana\",\n initialMessage,\n model,\n messages: externalMessages,\n onMessageSend,\n onResponseReceive,\n}: ChatPopupProps) => {\n const [input, setInput] = useState<string>(\"\");\n const [internalMessages, setInternalMessages] = useState<Message[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [internalPortfolioData, setInternalPortfolioData] = useState<any>(null);\n const [dimensions, setDimensions] = useState({ width: 330, height: 480 });\n const [isResizing, setIsResizing] = useState(false);\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n const activeMessages = externalMessages || internalMessages;\n const activePortfolioData = externalPortfolioData || internalPortfolioData;\n\n useEffect(() => {\n if (!externalMessages || externalMessages.length === 0) {\n if (internalMessages.length === 0) {\n const saved = localStorage.getItem(\"messages\");\n if (saved) {\n setInternalMessages(JSON.parse(saved));\n } else {\n setInternalMessages([\n {\n role: \"assistant\",\n content:\n initialMessage ||\n `Hi this is ${assistantName}! How can I help you today?`,\n },\n ]);\n }\n }\n }\n }, [\n externalMessages,\n initialMessage,\n assistantName,\n internalMessages.length,\n ]);\n\n useEffect(() => {\n if (!externalPortfolioData) {\n const fetchPortfolioData = async () => {\n try {\n const response = await fetch(\n \"https://raw.githubusercontent.com/hi-malay/portfolio-data/refs/heads/main/scrapped_data.json\",\n );\n const data = await response.json();\n setInternalPortfolioData(data);\n } catch (error) {\n console.error(\"Error fetching portfolio data:\", error);\n }\n };\n fetchPortfolioData();\n }\n }, [externalPortfolioData]);\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [activeMessages]);\n\n const getAIResponse = async (currentMessages: Message[]): Promise<string> => {\n const response = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n messages: currentMessages,\n portfolioData: activePortfolioData,\n systemPrompt,\n model,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || \"Failed to get AI response\");\n }\n\n const data = await response.json();\n if (onResponseReceive) onResponseReceive(data.text);\n return data.text;\n };\n\n const callModel = async (userInput: string) => {\n if (!userInput.trim() || isLoading) return;\n\n const userMessage: Message = { role: \"user\", content: userInput };\n if (onMessageSend) onMessageSend(userMessage);\n\n const newMessages = [...activeMessages, userMessage];\n\n if (!externalMessages) {\n setInternalMessages(newMessages);\n }\n\n setInput(\"\");\n setIsLoading(true);\n\n try {\n const text = await getAIResponse(newMessages);\n\n const assistantMessage: Message = {\n role: \"assistant\",\n content: text,\n };\n\n const updatedMessages = [...newMessages, assistantMessage];\n if (!externalMessages) {\n setInternalMessages(updatedMessages);\n localStorage.setItem(\"messages\", JSON.stringify(updatedMessages));\n }\n } catch (error) {\n console.error(\"Error calling AI:\", error);\n const defaultFailMessage: Message = {\n role: \"assistant\",\n content: \"Sorry, I encountered an error. Please try again later.\",\n };\n const updatedMessages = [...newMessages, defaultFailMessage];\n if (!externalMessages) {\n setInternalMessages(updatedMessages);\n localStorage.setItem(\"messages\", JSON.stringify(updatedMessages));\n }\n } finally {\n setIsLoading(false);\n }\n };\n\n useEffect(() => {\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 100)}px`;\n }\n }, [input]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n setIsResizing(true);\n }, []);\n\n useEffect(() => {\n if (!isResizing) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n if (!wrapperRef.current) return;\n\n const rect = wrapperRef.current.getBoundingClientRect();\n const newWidth = rect.right - e.clientX;\n const newHeight = rect.bottom - e.clientY;\n\n if (newWidth > 250 && newWidth < 800) {\n setDimensions((prev) => ({ ...prev, width: newWidth }));\n }\n if (newHeight > 300 && newHeight < 800) {\n setDimensions((prev) => ({ ...prev, height: newHeight }));\n }\n };\n\n const handleMouseUp = () => {\n setIsResizing(false);\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [isResizing]);\n\n return (\n <div\n ref={wrapperRef}\n className={`chat-popup-wrapper ${isResizing ? \"resizing\" : \"\"}`}\n style={{\n width: `${dimensions.width}px`,\n height: `${dimensions.height}px`,\n }}\n >\n <div className=\"stretch-icon\" onMouseDown={handleMouseDown}></div>\n <div className=\"messages-container\">\n {activeMessages.map((msg: Message, index: number) => (\n <div\n key={index}\n className={`message ${msg.role === \"user\" ? \"user\" : \"ai\"}`}\n >\n {msg.content}\n </div>\n ))}\n {isLoading && <div className=\"message ai loading\">Thinking...</div>}\n <div ref={messagesEndRef} />\n </div>\n\n <div className=\"input-container\">\n <textarea\n ref={textareaRef}\n rows={1}\n placeholder=\"What's on your mind?\"\n value={input}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n callModel(input);\n }\n }}\n onChange={(e) => setInput(e.target.value)}\n />\n <button\n onClick={() => callModel(input)}\n disabled={!input.trim() || isLoading}\n className=\"send-button\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["useState","useRef","useEffect","useCallback","jsx","jsxs","ChatPopup","systemPrompt","externalPortfolioData","apiUrl","assistantName","initialMessage","model","externalMessages","onMessageSend","onResponseReceive","input","setInput","useState","internalMessages","setInternalMessages","isLoading","setIsLoading","internalPortfolioData","setInternalPortfolioData","dimensions","setDimensions","isResizing","setIsResizing","wrapperRef","useRef","textareaRef","messagesEndRef","activeMessages","activePortfolioData","useEffect","saved","data","error","scrollToBottom","getAIResponse","currentMessages","response","errorData","callModel","userInput","userMessage","newMessages","assistantMessage","updatedMessages","defaultFailMessage","handleMouseDown","useCallback","handleMouseMove","e","rect","newWidth","newHeight","prev","handleMouseUp","msg","index"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-popup.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport \"./chat-popup.css\";\n\ntype Message = {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n};\n\nexport interface ChatPopupProps {\n systemPrompt?: string;\n portfolioData?: any;\n apiUrl?: string;\n assistantName?: string;\n initialMessage?: string;\n model?: string;\n messages?: Message[];\n onMessageSend?: (message: Message) => void;\n onResponseReceive?: (response: string) => void;\n mockMode?: boolean; // If true, uses mock responses instead of API calls\n position?: \"fixed\" | \"relative\"; // Position style for the wrapper\n}\n\nexport const ChatPopup = ({\n systemPrompt,\n portfolioData: externalPortfolioData,\n apiUrl = \"/chatbot\",\n assistantName = \"Thikana\",\n initialMessage,\n model,\n messages: externalMessages,\n onMessageSend,\n onResponseReceive,\n mockMode = false,\n position = \"relative\",\n}: ChatPopupProps) => {\n const [input, setInput] = useState<string>(\"\");\n const [internalMessages, setInternalMessages] = useState<Message[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [internalPortfolioData, setInternalPortfolioData] = useState<any>(null);\n const [dimensions, setDimensions] = useState({ width: 330, height: 480 });\n const [isResizing, setIsResizing] = useState(false);\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n\n const activeMessages = externalMessages || internalMessages;\n const activePortfolioData = externalPortfolioData || internalPortfolioData;\n\n useEffect(() => {\n if (!externalMessages || externalMessages.length === 0) {\n if (internalMessages.length === 0) {\n const saved = localStorage.getItem(\"messages\");\n if (saved) {\n setInternalMessages(JSON.parse(saved));\n } else {\n setInternalMessages([\n {\n role: \"assistant\",\n content:\n initialMessage ||\n `Hi this is ${assistantName}! How can I help you today?`,\n },\n ]);\n }\n }\n }\n }, [\n externalMessages,\n initialMessage,\n assistantName,\n internalMessages.length,\n ]);\n\n useEffect(() => {\n if (!externalPortfolioData) {\n const fetchPortfolioData = async () => {\n try {\n const response = await fetch(\n \"https://raw.githubusercontent.com/hi-malay/portfolio-data/refs/heads/main/scrapped_data.json\",\n );\n const data = await response.json();\n setInternalPortfolioData(data);\n } catch (error) {\n console.error(\"Error fetching portfolio data:\", error);\n }\n };\n fetchPortfolioData();\n }\n }, [externalPortfolioData]);\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [activeMessages]);\n\n const getAIResponse = async (currentMessages: Message[]): Promise<string> => {\n // Mock mode for testing without API\n if (mockMode) {\n await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate API delay\n const mockResponses = [\n \"That's an interesting question! Let me help you with that.\",\n \"I understand what you're asking. Here's what I think...\",\n \"Great question! Based on what you've told me, I'd suggest...\",\n \"Let me break that down for you.\",\n \"I'm here to help! Here's my take on that...\",\n ];\n const response =\n mockResponses[Math.floor(Math.random() * mockResponses.length)];\n if (onResponseReceive) onResponseReceive(response);\n return response;\n }\n\n const response = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n messages: currentMessages,\n portfolioData: activePortfolioData,\n systemPrompt,\n model,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || \"Failed to get AI response\");\n }\n\n const data = await response.json();\n if (onResponseReceive) onResponseReceive(data.text);\n return data.text;\n };\n\n const callModel = async (userInput: string) => {\n if (!userInput.trim() || isLoading) return;\n\n const userMessage: Message = { role: \"user\", content: userInput };\n if (onMessageSend) onMessageSend(userMessage);\n\n const newMessages = [...activeMessages, userMessage];\n\n if (!externalMessages) {\n setInternalMessages(newMessages);\n }\n\n setInput(\"\");\n setIsLoading(true);\n\n try {\n const text = await getAIResponse(newMessages);\n\n const assistantMessage: Message = {\n role: \"assistant\",\n content: text,\n };\n\n const updatedMessages = [...newMessages, assistantMessage];\n if (!externalMessages) {\n setInternalMessages(updatedMessages);\n localStorage.setItem(\"messages\", JSON.stringify(updatedMessages));\n }\n } catch (error) {\n console.error(\"Error calling AI:\", error);\n const defaultFailMessage: Message = {\n role: \"assistant\",\n content: \"Sorry, I encountered an error. Please try again later.\",\n };\n const updatedMessages = [...newMessages, defaultFailMessage];\n if (!externalMessages) {\n setInternalMessages(updatedMessages);\n localStorage.setItem(\"messages\", JSON.stringify(updatedMessages));\n }\n } finally {\n setIsLoading(false);\n }\n };\n\n useEffect(() => {\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\";\n textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 100)}px`;\n }\n }, [input]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n setIsResizing(true);\n }, []);\n\n useEffect(() => {\n if (!isResizing) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n if (!wrapperRef.current) return;\n\n const rect = wrapperRef.current.getBoundingClientRect();\n const newWidth = rect.right - e.clientX;\n const newHeight = rect.bottom - e.clientY;\n\n if (newWidth > 250 && newWidth < 800) {\n setDimensions((prev) => ({ ...prev, width: newWidth }));\n }\n if (newHeight > 300 && newHeight < 800) {\n setDimensions((prev) => ({ ...prev, height: newHeight }));\n }\n };\n\n const handleMouseUp = () => {\n setIsResizing(false);\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [isResizing]);\n\n return (\n <div\n ref={wrapperRef}\n className={`chat-popup-wrapper ${isResizing ? \"resizing\" : \"\"}`}\n style={{\n width: `${dimensions.width}px`,\n height: `${dimensions.height}px`,\n position: position,\n }}\n >\n <div className=\"stretch-icon\" onMouseDown={handleMouseDown}></div>\n <div className=\"messages-container\">\n {activeMessages.map((msg: Message, index: number) => (\n <div\n key={index}\n className={`message ${msg.role === \"user\" ? \"user\" : \"ai\"}`}\n >\n {msg.content}\n </div>\n ))}\n {isLoading && <div className=\"message ai loading\">Thinking...</div>}\n <div ref={messagesEndRef} />\n </div>\n\n <div className=\"input-container\">\n <textarea\n ref={textareaRef}\n rows={1}\n placeholder=\"What's on your mind?\"\n value={input}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n callModel(input);\n }\n }}\n onChange={(e) => setInput(e.target.value)}\n />\n <button\n onClick={() => callModel(input)}\n disabled={!input.trim() || isLoading}\n className=\"send-button\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["useState","useRef","useEffect","useCallback","jsx","jsxs","ChatPopup","systemPrompt","externalPortfolioData","apiUrl","assistantName","initialMessage","model","externalMessages","onMessageSend","onResponseReceive","mockMode","position","input","setInput","useState","internalMessages","setInternalMessages","isLoading","setIsLoading","internalPortfolioData","setInternalPortfolioData","dimensions","setDimensions","isResizing","setIsResizing","wrapperRef","useRef","textareaRef","messagesEndRef","activeMessages","activePortfolioData","useEffect","saved","data","error","scrollToBottom","getAIResponse","currentMessages","resolve","mockResponses","response","errorData","callModel","userInput","userMessage","newMessages","assistantMessage","updatedMessages","defaultFailMessage","handleMouseDown","useCallback","handleMouseMove","e","rect","newWidth","newHeight","prev","handleMouseUp","msg","index"]}
|