thikanaa 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -0
- package/dist/index.css +112 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +77 -0
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# [Thikana](https://thikana.malaymishra.com/)
|
|
2
|
+
|
|
3
|
+
**Thikana** (meaning "Destination" or "Home" in Hindi) is a premium AI-powered portfolio assistant designed to provide an interactive way to explore details of your project.
|
|
4
|
+
|
|
5
|
+
Built with modern web technologies, Thikana offers a seamless, conversational interface that acts as a digital twin for your app, answering questions about his experience, skills, and projects in real-time.
|
|
6
|
+
|
|
7
|
+
## ✨ Features
|
|
8
|
+
|
|
9
|
+
- **Multi-Model AI Integration**: Leverages the power of **Groq** (Llama 3.3, 3.1) and **Google Gemini** (1.5 Flash) via the Vercel AI SDK.
|
|
10
|
+
- **Intelligent Fallback Mechanism**: If one AI model is unavailable or hits rate limits, the system automatically tries the next best model to ensure zero downtime.
|
|
11
|
+
- **Dynamic Context Injection**: Responds accurately based on a comprehensive professional dataset (experience at Adeptmind, expertise in Go, Python, React, and more).
|
|
12
|
+
- **Modern UI/UX**: Features a sleek, responsive chat interface with glassmorphism effects and smooth micro-animations.
|
|
13
|
+
- **Persistent Chat History**: Remembers your conversation using local storage.
|
|
14
|
+
|
|
15
|
+
## 🛠️ Tech Stack
|
|
16
|
+
|
|
17
|
+
- **Frontend**: [Next.js](https://nextjs.org/) (App Router), React 19, TypeScript
|
|
18
|
+
- **Styling**: Vanilla CSS (Modern CSS variables, Flexbox/Grid)
|
|
19
|
+
- **AI Engine**: [Vercel AI SDK](https://sdk.vercel.ai/docs), Groq, Google Generative AI
|
|
20
|
+
- **Deployment**: Optimized for Vercel
|
|
21
|
+
|
|
22
|
+
## 🚀 Getting Started
|
|
23
|
+
|
|
24
|
+
### Prerequisites
|
|
25
|
+
|
|
26
|
+
- Node.js (v18 or later)
|
|
27
|
+
- Yarn or NPM
|
|
28
|
+
- API Keys for Groq and/or Google Gemini
|
|
29
|
+
|
|
30
|
+
### Installation
|
|
31
|
+
|
|
32
|
+
1. **Clone the repository**:
|
|
33
|
+
```bash
|
|
34
|
+
git clone [repository-url]
|
|
35
|
+
cd thikana
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
2. **Install dependencies**:
|
|
39
|
+
```bash
|
|
40
|
+
yarn install
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
3. **Set up Environment Variables**:
|
|
44
|
+
Create a `.env` file in the root directory and add your API keys:
|
|
45
|
+
```env
|
|
46
|
+
GROQ_API_KEY=your_groq_api_key_here
|
|
47
|
+
GEMINI_API_KEY=your_gemini_api_key_here
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
4. **Run the development server**:
|
|
51
|
+
```bash
|
|
52
|
+
yarn dev
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
5. **Open the app**:
|
|
56
|
+
Navigate to [http://localhost:3000](http://localhost:3000) to see the application in action.
|
|
57
|
+
|
|
58
|
+
## 📦 NPM Package Usage
|
|
59
|
+
|
|
60
|
+
You can now use Thikana as an npm package in your own React/Next.js projects.
|
|
61
|
+
|
|
62
|
+
### Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm install thikanaa
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Usage
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { ChatPopup } from 'thikanaa';
|
|
72
|
+
import 'thikanaa/dist/index.css';
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
const App = () => {
|
|
76
|
+
return (
|
|
77
|
+
<ChatPopup
|
|
78
|
+
systemPrompt="Your custom system prompt here"
|
|
79
|
+
assistantName="Thikana"
|
|
80
|
+
apiUrl="/api/chatbot" // Your backend endpoint
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Props
|
|
87
|
+
|
|
88
|
+
| Prop | Type | Description |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| `systemPrompt` | `string` | Custom instructions for the AI model |
|
|
91
|
+
| `portfolioData` | `any` | Base context data for the assistant |
|
|
92
|
+
| `apiUrl` | `string` | Endpoint to call for AI responses (default: `/chatbot`) |
|
|
93
|
+
| `assistantName` | `string` | Name shown in the chat (default: `Thikana`) |
|
|
94
|
+
| `model` | `string` | Specific model ID to use |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
Crafted with ❤️ by **Malay Mishra**
|
|
99
|
+
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
.chat-popup-wrapper {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
height: 100%;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.input-container {
|
|
8
|
+
margin-top: auto;
|
|
9
|
+
width: 100%;
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: flex-end;
|
|
12
|
+
gap: 10px;
|
|
13
|
+
background-color: #f8f9fa;
|
|
14
|
+
padding: 4px 6px;
|
|
15
|
+
border-radius: 20px;
|
|
16
|
+
border: 1px solid #e9ecef;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.input-container textarea {
|
|
21
|
+
flex: 1;
|
|
22
|
+
border: none;
|
|
23
|
+
background: transparent;
|
|
24
|
+
padding: 6px 8px;
|
|
25
|
+
font-size: 14px;
|
|
26
|
+
line-height: 20px;
|
|
27
|
+
outline: none;
|
|
28
|
+
resize: none;
|
|
29
|
+
font-family: inherit;
|
|
30
|
+
overflow-y: auto;
|
|
31
|
+
max-height: 100px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.input-container textarea::placeholder {
|
|
35
|
+
color: #adb5bd;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.input-container .send-button {
|
|
39
|
+
background: #c52c2cba;
|
|
40
|
+
color: white;
|
|
41
|
+
border: none;
|
|
42
|
+
border-radius: 50%;
|
|
43
|
+
width: 32px;
|
|
44
|
+
height: 32px;
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
transition: background-color 0.2s;
|
|
50
|
+
flex-shrink: 0;
|
|
51
|
+
padding: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.input-container .send-button:hover:not(:disabled) {
|
|
55
|
+
background-color: #c52c2c;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.input-container .send-button:disabled {
|
|
59
|
+
opacity: 0.5;
|
|
60
|
+
cursor: not-allowed;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.messages-container {
|
|
64
|
+
flex: 1;
|
|
65
|
+
overflow-y: auto;
|
|
66
|
+
margin-bottom: 10px;
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
gap: 12px;
|
|
70
|
+
padding-right: 4px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.messages-container::-webkit-scrollbar {
|
|
74
|
+
width: 4px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.messages-container::-webkit-scrollbar-track {
|
|
78
|
+
background: transparent;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.messages-container::-webkit-scrollbar-thumb {
|
|
82
|
+
background: #e9ecef;
|
|
83
|
+
border-radius: 10px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.message {
|
|
87
|
+
max-width: 85%;
|
|
88
|
+
padding: 10px 14px;
|
|
89
|
+
border-radius: 18px;
|
|
90
|
+
font-size: 14px;
|
|
91
|
+
line-height: 1.4;
|
|
92
|
+
word-wrap: break-word;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.message.user {
|
|
96
|
+
align-self: flex-end;
|
|
97
|
+
background-color: #c52c2cba;
|
|
98
|
+
color: white;
|
|
99
|
+
border-bottom-right-radius: 4px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.message.ai {
|
|
103
|
+
align-self: flex-start;
|
|
104
|
+
background-color: #f1f3f5;
|
|
105
|
+
color: #212529;
|
|
106
|
+
border-bottom-left-radius: 4px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.message.loading {
|
|
110
|
+
font-style: italic;
|
|
111
|
+
color: #868e96;
|
|
112
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-popup.css"],"sourcesContent":[".chat-popup-wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.input-container {\n margin-top: auto;\n width: 100%;\n display: flex;\n align-items: flex-end;\n gap: 10px;\n background-color: #f8f9fa;\n padding: 4px 6px;\n border-radius: 20px;\n border: 1px solid #e9ecef;\n box-sizing: border-box;\n}\n\n.input-container textarea {\n flex: 1;\n border: none;\n background: transparent;\n padding: 6px 8px;\n font-size: 14px;\n line-height: 20px;\n outline: none;\n resize: none;\n font-family: inherit;\n overflow-y: auto;\n max-height: 100px;\n}\n\n.input-container textarea::placeholder {\n color: #adb5bd;\n}\n\n.input-container .send-button {\n background: #c52c2cba;\n color: white;\n border: none;\n border-radius: 50%;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: background-color 0.2s;\n flex-shrink: 0;\n padding: 0;\n}\n\n.input-container .send-button:hover:not(:disabled) {\n background-color: #c52c2c;\n}\n\n.input-container .send-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.messages-container {\n flex: 1;\n overflow-y: auto;\n margin-bottom: 10px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding-right: 4px;\n}\n\n.messages-container::-webkit-scrollbar {\n width: 4px;\n}\n\n.messages-container::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.messages-container::-webkit-scrollbar-thumb {\n background: #e9ecef;\n border-radius: 10px;\n}\n\n.message {\n max-width: 85%;\n padding: 10px 14px;\n border-radius: 18px;\n font-size: 14px;\n line-height: 1.4;\n word-wrap: break-word;\n}\n\n.message.user {\n align-self: flex-end;\n background-color: #c52c2cba;\n color: white;\n border-bottom-right-radius: 4px;\n}\n\n.message.ai {\n align-self: flex-start;\n background-color: #f1f3f5;\n color: #212529;\n border-bottom-left-radius: 4px;\n}\n\n.message.loading {\n font-style: italic;\n color: #868e96;\n}\n"],"mappings":"AAAA,CAAC,mBACC,QAAS,KACT,eAAgB,OAChB,OAAQ,IACV,CAEA,CAAC,gBACC,WAAY,KACZ,MAAO,KACP,QAAS,KACT,YAAa,SACb,IAAK,KACL,iBAAkB,QAZpB,QAaW,IAAI,IAbf,cAciB,KACf,OAAQ,IAAI,MAAM,QAClB,WAAY,UACd,CAEA,CAbC,gBAagB,SACf,KAAM,EACN,OAAQ,KACR,WAAY,YAtBd,QAuBW,IAAI,IACb,UAAW,KACX,YAAa,KACb,QAAS,KACT,OAAQ,KACR,YAAa,QACb,WAAY,KACZ,WAAY,KACd,CAEA,CA3BC,gBA2BgB,QAAQ,cACvB,MAAO,OACT,CAEA,CA/BC,gBA+BgB,CAAC,YAChB,WAAY,UACZ,MAAO,KACP,OAAQ,KAxCV,cAyCiB,IACf,MAAO,KACP,OAAQ,KACR,QAAS,KACT,YAAa,OACb,gBAAiB,OACjB,OAAQ,QACR,WAAY,iBAAiB,IAC7B,YAAa,EAjDf,QAkDW,CACX,CAEA,CA/CC,gBA+CgB,CAhBC,WAgBW,MAAM,KAAK,WACtC,iBAAkB,OACpB,CAEA,CAnDC,gBAmDgB,CApBC,WAoBW,UAC3B,QAAS,GACT,OAAQ,WACV,CAEA,CAAC,mBACC,KAAM,EACN,WAAY,KACZ,cAAe,KACf,QAAS,KACT,eAAgB,OAChB,IAAK,KACL,cAAe,GACjB,CAEA,CAVC,kBAUkB,oBACjB,MAAO,GACT,CAEA,CAdC,kBAckB,0BACjB,WAAY,WACd,CAEA,CAlBC,kBAkBkB,0BACjB,WAAY,QAjFd,cAkFiB,IACjB,CAEA,CAAC,QACC,UAAW,IAtFb,QAuFW,KAAK,KAvFhB,cAwFiB,KACf,UAAW,KACX,YAAa,IACb,UAAW,UACb,CAEA,CATC,OASO,CAAC,KACP,WAAY,SACZ,iBAAkB,UAClB,MAAO,KACP,2BAA4B,GAC9B,CAEA,CAhBC,OAgBO,CAAC,GACP,WAAY,WACZ,iBAAkB,QAClB,MAAO,QACP,0BAA2B,GAC7B,CAEA,CAvBC,OAuBO,CAAC,QACP,WAAY,OACZ,MAAO,OACT","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type Message = {
|
|
4
|
+
role: "user" | "assistant" | "system";
|
|
5
|
+
content: string;
|
|
6
|
+
};
|
|
7
|
+
interface ChatPopupProps {
|
|
8
|
+
systemPrompt?: string;
|
|
9
|
+
portfolioData?: any;
|
|
10
|
+
apiUrl?: string;
|
|
11
|
+
assistantName?: string;
|
|
12
|
+
initialMessage?: string;
|
|
13
|
+
model?: string;
|
|
14
|
+
messages?: Message[];
|
|
15
|
+
onMessageSend?: (message: Message) => void;
|
|
16
|
+
onResponseReceive?: (response: string) => void;
|
|
17
|
+
}
|
|
18
|
+
declare const ChatPopup: ({ systemPrompt, portfolioData: externalPortfolioData, apiUrl, assistantName, initialMessage, model, messages: externalMessages, onMessageSend, onResponseReceive, }: ChatPopupProps) => react_jsx_runtime.JSX.Element;
|
|
19
|
+
|
|
20
|
+
export { ChatPopup, type ChatPopupProps };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type Message = {
|
|
4
|
+
role: "user" | "assistant" | "system";
|
|
5
|
+
content: string;
|
|
6
|
+
};
|
|
7
|
+
interface ChatPopupProps {
|
|
8
|
+
systemPrompt?: string;
|
|
9
|
+
portfolioData?: any;
|
|
10
|
+
apiUrl?: string;
|
|
11
|
+
assistantName?: string;
|
|
12
|
+
initialMessage?: string;
|
|
13
|
+
model?: string;
|
|
14
|
+
messages?: Message[];
|
|
15
|
+
onMessageSend?: (message: Message) => void;
|
|
16
|
+
onResponseReceive?: (response: string) => void;
|
|
17
|
+
}
|
|
18
|
+
declare const ChatPopup: ({ systemPrompt, portfolioData: externalPortfolioData, apiUrl, assistantName, initialMessage, model, messages: externalMessages, onMessageSend, onResponseReceive, }: ChatPopupProps) => react_jsx_runtime.JSX.Element;
|
|
19
|
+
|
|
20
|
+
export { ChatPopup, type ChatPopupProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var w=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var O=Object.prototype.hasOwnProperty;var R=(n,t)=>{for(var l in t)w(n,l,{get:t[l],enumerable:!0})},z=(n,t,l,d)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of H(t))!O.call(n,i)&&i!==l&&w(n,i,{get:()=>t[i],enumerable:!(d=L(t,i))||d.enumerable});return n};var A=n=>z(w({},"__esModule",{value:!0}),n);var $={};R($,{ChatPopup:()=>J});module.exports=A($);var s=require("react");var o=require("react/jsx-runtime"),J=({systemPrompt:n,portfolioData:t,apiUrl:l="/chatbot",assistantName:d="Thikana",initialMessage:i,model:N,messages:c,onMessageSend:v,onResponseReceive:k})=>{let[p,M]=(0,s.useState)(""),[m,g]=(0,s.useState)([]),[b,I]=(0,s.useState)(!1),[S,E]=(0,s.useState)(null),u=(0,s.useRef)(null),P=(0,s.useRef)(null),x=c||m,T=t||S;(0,s.useEffect)(()=>{if((!c||c.length===0)&&m.length===0){let e=localStorage.getItem("messages");g(e?JSON.parse(e):[{role:"assistant",content:i||`Hi this is ${d}! How can I help you today?`}])}},[c,i,d,m.length]),(0,s.useEffect)(()=>{t||(async()=>{try{let r=await(await fetch("https://raw.githubusercontent.com/hi-malay/portfolio-data/refs/heads/main/scrapped_data.json")).json();E(r)}catch(a){console.error("Error fetching portfolio data:",a)}})()},[t]);let C=()=>{P.current?.scrollIntoView({behavior:"smooth"})};(0,s.useEffect)(()=>{C()},[x]);let j=async e=>{let a=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messages:e,portfolioData:T,systemPrompt:n,model:N})});if(!a.ok){let h=await a.json();throw new Error(h.error||"Failed to get AI response")}let r=await a.json();return k&&k(r.text),r.text},D=async e=>{if(!e.trim()||b)return;let a={role:"user",content:e};v&&v(a);let r=[...x,a];c||g(r),M(""),I(!0);try{let y={role:"assistant",content:await j(r)},f=[...r,y];c||(g(f),localStorage.setItem("messages",JSON.stringify(f)))}catch(h){console.error("Error calling AI:",h);let y={role:"assistant",content:"Sorry, I encountered an error. Please try again later."},f=[...r,y];c||(g(f),localStorage.setItem("messages",JSON.stringify(f)))}finally{I(!1)}};return(0,s.useEffect)(()=>{u.current&&(u.current.style.height="auto",u.current.style.height=`${Math.min(u.current.scrollHeight,100)}px`)},[p]),(0,o.jsxs)("div",{className:"chat-popup-wrapper",children:[(0,o.jsxs)("div",{className:"messages-container",children:[x.map((e,a)=>(0,o.jsx)("div",{className:`message ${e.role==="user"?"user":"ai"}`,children:e.content},a)),b&&(0,o.jsx)("div",{className:"message ai loading",children:"Thinking..."}),(0,o.jsx)("div",{ref:P})]}),(0,o.jsxs)("div",{className:"input-container",children:[(0,o.jsx)("textarea",{ref:u,rows:1,placeholder:"What's on your mind?",value:p,onKeyDown:e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),D(p))},onChange:e=>M(e.target.value)}),(0,o.jsx)("button",{onClick:()=>D(p),disabled:!p.trim()||b,className:"send-button",children:(0,o.jsxs)("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,o.jsx)("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),(0,o.jsx)("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})})]})]})};0&&(module.exports={ChatPopup});
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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 } 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\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 return (\n <div className=\"chat-popup-wrapper\">\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","textareaRef","messagesEndRef","activeMessages","activePortfolioData","saved","data","error","scrollToBottom","getAIResponse","currentMessages","response","errorData","callModel","userInput","userMessage","newMessages","assistantMessage","updatedMessages","defaultFailMessage","msg","index"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{useState as d,useRef as D,useEffect as p}from"react";import{jsx as a,jsxs as g}from"react/jsx-runtime";var $=({systemPrompt:N,portfolioData:u,apiUrl:S="/chatbot",assistantName:x="Thikana",initialMessage:y,model:E,messages:s,onMessageSend:w,onResponseReceive:v})=>{let[n,k]=d(""),[f,r]=d([]),[h,M]=d(!1),[T,C]=d(null),i=D(null),I=D(null),m=s||f,j=u||T;p(()=>{if((!s||s.length===0)&&f.length===0){let e=localStorage.getItem("messages");r(e?JSON.parse(e):[{role:"assistant",content:y||`Hi this is ${x}! How can I help you today?`}])}},[s,y,x,f.length]),p(()=>{u||(async()=>{try{let o=await(await fetch("https://raw.githubusercontent.com/hi-malay/portfolio-data/refs/heads/main/scrapped_data.json")).json();C(o)}catch(t){console.error("Error fetching portfolio data:",t)}})()},[u]);let L=()=>{I.current?.scrollIntoView({behavior:"smooth"})};p(()=>{L()},[m]);let H=async e=>{let t=await fetch(S,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messages:e,portfolioData:j,systemPrompt:N,model:E})});if(!t.ok){let l=await t.json();throw new Error(l.error||"Failed to get AI response")}let o=await t.json();return v&&v(o.text),o.text},P=async e=>{if(!e.trim()||h)return;let t={role:"user",content:e};w&&w(t);let o=[...m,t];s||r(o),k(""),M(!0);try{let b={role:"assistant",content:await H(o)},c=[...o,b];s||(r(c),localStorage.setItem("messages",JSON.stringify(c)))}catch(l){console.error("Error calling AI:",l);let b={role:"assistant",content:"Sorry, I encountered an error. Please try again later."},c=[...o,b];s||(r(c),localStorage.setItem("messages",JSON.stringify(c)))}finally{M(!1)}};return p(()=>{i.current&&(i.current.style.height="auto",i.current.style.height=`${Math.min(i.current.scrollHeight,100)}px`)},[n]),g("div",{className:"chat-popup-wrapper",children:[g("div",{className:"messages-container",children:[m.map((e,t)=>a("div",{className:`message ${e.role==="user"?"user":"ai"}`,children:e.content},t)),h&&a("div",{className:"message ai loading",children:"Thinking..."}),a("div",{ref:I})]}),g("div",{className:"input-container",children:[a("textarea",{ref:i,rows:1,placeholder:"What's on your mind?",value:n,onKeyDown:e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),P(n))},onChange:e=>k(e.target.value)}),a("button",{onClick:()=>P(n),disabled:!n.trim()||h,className:"send-button",children:g("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{$ as ChatPopup};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-popup.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } 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\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 return (\n <div className=\"chat-popup-wrapper\">\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","jsx","jsxs","ChatPopup","systemPrompt","externalPortfolioData","apiUrl","assistantName","initialMessage","model","externalMessages","onMessageSend","onResponseReceive","input","setInput","useState","internalMessages","setInternalMessages","isLoading","setIsLoading","internalPortfolioData","setInternalPortfolioData","textareaRef","useRef","messagesEndRef","activeMessages","activePortfolioData","useEffect","saved","data","error","scrollToBottom","getAIResponse","currentMessages","response","errorData","callModel","userInput","userMessage","newMessages","assistantMessage","updatedMessages","defaultFailMessage","msg","index"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "thikanaa",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A beautiful, AI-powered chat popup component for React and Next.js applications",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"nextjs",
|
|
8
|
+
"chat",
|
|
9
|
+
"chatbot",
|
|
10
|
+
"ai",
|
|
11
|
+
"popup",
|
|
12
|
+
"component"
|
|
13
|
+
],
|
|
14
|
+
"author": "Malay Mishra",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"module": "./dist/index.mjs",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.mjs",
|
|
23
|
+
"require": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./dist/index.css": "./dist/index.css"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@ai-sdk/google": "^3.0.15",
|
|
32
|
+
"@ai-sdk/groq": "^3.0.16",
|
|
33
|
+
"@ai-sdk/openai": "^3.0.21",
|
|
34
|
+
"ai": "^6.0.57",
|
|
35
|
+
"zod": "^4.3.6"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"next": ">=13",
|
|
39
|
+
"react": ">=18",
|
|
40
|
+
"react-dom": ">=18"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"dev": "next dev",
|
|
47
|
+
"build": "next build",
|
|
48
|
+
"build:lib": "tsup",
|
|
49
|
+
"prepublishOnly": "npm run build:lib",
|
|
50
|
+
"start": "next start",
|
|
51
|
+
"lint": "next lint"
|
|
52
|
+
},
|
|
53
|
+
"eslintConfig": {
|
|
54
|
+
"extends": [
|
|
55
|
+
"react-app",
|
|
56
|
+
"react-app/jest"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"browserslist": {
|
|
60
|
+
"production": [
|
|
61
|
+
">0.2%",
|
|
62
|
+
"not dead",
|
|
63
|
+
"not op_mini all"
|
|
64
|
+
],
|
|
65
|
+
"development": [
|
|
66
|
+
"last 1 chrome version",
|
|
67
|
+
"last 1 firefox version",
|
|
68
|
+
"last 1 safari version"
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@types/node": "25.1.0",
|
|
73
|
+
"@types/react": "19.2.10",
|
|
74
|
+
"tsup": "^8.5.1",
|
|
75
|
+
"typescript": "^5.9.3"
|
|
76
|
+
}
|
|
77
|
+
}
|