goji-search 1.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.
Files changed (25) hide show
  1. package/README.md +70 -0
  2. package/dist/goji-search/components/elements/action-buttons.d.ts +12 -0
  3. package/dist/goji-search/components/elements/action-buttons.js +135 -0
  4. package/dist/goji-search/components/elements/calendar-integration.d.ts +5 -0
  5. package/dist/goji-search/components/elements/calendar-integration.js +49 -0
  6. package/dist/goji-search/components/elements/inspiration-menu.d.ts +7 -0
  7. package/dist/goji-search/components/elements/inspiration-menu.js +79 -0
  8. package/dist/goji-search/components/elements/message-list.d.ts +24 -0
  9. package/dist/goji-search/components/elements/message-list.js +293 -0
  10. package/dist/goji-search/components/elements/search-input.d.ts +15 -0
  11. package/dist/goji-search/components/elements/search-input.js +90 -0
  12. package/dist/goji-search/components/elements/suggested-questions.d.ts +6 -0
  13. package/dist/goji-search/components/elements/suggested-questions.js +54 -0
  14. package/dist/goji-search/components/goji-search-component.d.ts +2 -0
  15. package/dist/goji-search/components/goji-search-component.js +505 -0
  16. package/dist/goji-search/config/company.d.ts +29 -0
  17. package/dist/goji-search/config/company.js +68 -0
  18. package/dist/goji-search/lib/calendar-config.d.ts +9 -0
  19. package/dist/goji-search/lib/calendar-config.js +10 -0
  20. package/dist/goji-search/lib/goji-client.d.ts +81 -0
  21. package/dist/goji-search/lib/goji-client.js +176 -0
  22. package/dist/goji-search.css +1 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +2 -0
  25. package/package.json +47 -0
@@ -0,0 +1,81 @@
1
+ /**
2
+ * GojiSearch API Client
3
+ * Handles both HTTP and WebSocket connections to the GojiSearch backend
4
+ */
5
+ export interface ChatMessage {
6
+ role: "user" | "assistant";
7
+ content: string;
8
+ timestamp: number;
9
+ }
10
+ export interface ChatSource {
11
+ index: number;
12
+ url: string;
13
+ title: string;
14
+ domain: string;
15
+ page_type: string;
16
+ score: number;
17
+ }
18
+ export interface ChatResponse {
19
+ session_id: string;
20
+ answer: string;
21
+ sources: ChatSource[];
22
+ }
23
+ export interface StreamDeltaMessage {
24
+ type: "chat_delta";
25
+ delta: string;
26
+ }
27
+ export interface StreamDoneMessage {
28
+ type: "chat_done";
29
+ session_id: string;
30
+ answer: string;
31
+ sources: ChatSource[];
32
+ }
33
+ export type StreamMessage = StreamDeltaMessage | StreamDoneMessage;
34
+ export declare class GojiSearchClient {
35
+ private baseUrl;
36
+ private wsUrl;
37
+ private ws;
38
+ private currentHandler;
39
+ private reconnectAttempts;
40
+ private maxReconnectAttempts;
41
+ constructor(baseUrl?: string);
42
+ private ensureWebSocketConnection;
43
+ closeWebSocket(): void;
44
+ /**
45
+ * Send a chat message (non-streaming)
46
+ */
47
+ chat(params: {
48
+ message: string;
49
+ sessionId?: string;
50
+ limit?: number;
51
+ language?: string;
52
+ }): Promise<ChatResponse>;
53
+ /**
54
+ * Send a chat message with streaming (WebSocket)
55
+ * Reuses existing WebSocket connection
56
+ */
57
+ streamChat(params: {
58
+ message: string;
59
+ sessionId?: string;
60
+ limit?: number;
61
+ language?: string;
62
+ onDelta: (delta: string) => void;
63
+ onDone: (response: ChatResponse) => void;
64
+ onError: (error: Error) => void;
65
+ }): Promise<() => void>;
66
+ /**
67
+ * Get chat history for a session
68
+ */
69
+ getHistory(sessionId: string): Promise<{
70
+ history: ChatMessage[];
71
+ }>;
72
+ /**
73
+ * Clear a chat session
74
+ */
75
+ clearSession(sessionId: string): Promise<void>;
76
+ /**
77
+ * Health check
78
+ */
79
+ health(): Promise<any>;
80
+ }
81
+ export declare const gojiClient: GojiSearchClient;
@@ -0,0 +1,176 @@
1
+ /**
2
+ * GojiSearch API Client
3
+ * Handles both HTTP and WebSocket connections to the GojiSearch backend
4
+ */
5
+ export class GojiSearchClient {
6
+ baseUrl;
7
+ wsUrl;
8
+ ws = null;
9
+ currentHandler = null;
10
+ reconnectAttempts = 0;
11
+ maxReconnectAttempts = 3;
12
+ constructor(baseUrl = "http://localhost:8000") {
13
+ this.baseUrl = baseUrl;
14
+ this.wsUrl = baseUrl.replace(/^http/, "ws");
15
+ }
16
+ ensureWebSocketConnection() {
17
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
18
+ return Promise.resolve();
19
+ }
20
+ return new Promise((resolve, reject) => {
21
+ this.ws = new WebSocket(`${this.wsUrl}/ws/chat`);
22
+ this.ws.onopen = () => {
23
+ console.log("[GojiSearch] WebSocket connected");
24
+ this.reconnectAttempts = 0;
25
+ resolve();
26
+ };
27
+ this.ws.onmessage = (event) => {
28
+ try {
29
+ const data = JSON.parse(event.data);
30
+ console.log("[GojiSearch] WebSocket message:", data.type, data);
31
+ if (data.type === "ready") {
32
+ console.log("[GojiSearch] WebSocket ready");
33
+ }
34
+ else if (data.type === "chat_delta") {
35
+ if (this.currentHandler) {
36
+ console.log("[GojiSearch] Delta:", data.delta);
37
+ this.currentHandler.onDelta(data.delta);
38
+ }
39
+ }
40
+ else if (data.type === "chat_done") {
41
+ console.log("[GojiSearch] Chat done, answer length:", data.answer?.length, "sources:", data.sources?.length);
42
+ if (this.currentHandler) {
43
+ this.currentHandler.onDone({
44
+ session_id: data.session_id,
45
+ answer: data.answer,
46
+ sources: data.sources,
47
+ });
48
+ // Clear handler after completion
49
+ this.currentHandler = null;
50
+ }
51
+ }
52
+ else if (data.type === "error") {
53
+ if (this.currentHandler) {
54
+ this.currentHandler.onError(new Error(data.error || "Unknown error"));
55
+ this.currentHandler = null;
56
+ }
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.error("[GojiSearch] Parse error:", error);
61
+ if (this.currentHandler) {
62
+ this.currentHandler.onError(error);
63
+ this.currentHandler = null;
64
+ }
65
+ }
66
+ };
67
+ this.ws.onerror = (event) => {
68
+ console.error("[GojiSearch] WebSocket error");
69
+ reject(new Error("WebSocket connection failed"));
70
+ };
71
+ this.ws.onclose = (event) => {
72
+ console.log("[GojiSearch] WebSocket closed");
73
+ this.ws = null;
74
+ // Attempt reconnect if not a clean close
75
+ if (!event.wasClean && this.reconnectAttempts < this.maxReconnectAttempts) {
76
+ this.reconnectAttempts++;
77
+ console.log(`[GojiSearch] Reconnecting (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
78
+ setTimeout(() => this.ensureWebSocketConnection(), 1000 * this.reconnectAttempts);
79
+ }
80
+ };
81
+ });
82
+ }
83
+ closeWebSocket() {
84
+ if (this.ws) {
85
+ this.ws.close();
86
+ this.ws = null;
87
+ }
88
+ this.currentHandler = null;
89
+ }
90
+ /**
91
+ * Send a chat message (non-streaming)
92
+ */
93
+ async chat(params) {
94
+ const response = await fetch(`${this.baseUrl}/chat`, {
95
+ method: "POST",
96
+ headers: {
97
+ "Content-Type": "application/json",
98
+ },
99
+ body: JSON.stringify({
100
+ message: params.message,
101
+ session_id: params.sessionId,
102
+ limit: params.limit || 5,
103
+ language: params.language,
104
+ }),
105
+ });
106
+ if (!response.ok) {
107
+ throw new Error(`Chat request failed: ${response.statusText}`);
108
+ }
109
+ return response.json();
110
+ }
111
+ /**
112
+ * Send a chat message with streaming (WebSocket)
113
+ * Reuses existing WebSocket connection
114
+ */
115
+ async streamChat(params) {
116
+ try {
117
+ // Ensure WebSocket is connected
118
+ await this.ensureWebSocketConnection();
119
+ // Set current handler (only one message at a time)
120
+ this.currentHandler = {
121
+ onDelta: params.onDelta,
122
+ onDone: params.onDone,
123
+ onError: params.onError,
124
+ };
125
+ console.log("[GojiSearch] Sending message:", params.message);
126
+ // Send message
127
+ this.ws.send(JSON.stringify({
128
+ message: params.message,
129
+ session_id: params.sessionId,
130
+ limit: params.limit || 5,
131
+ stream: true,
132
+ language: params.language,
133
+ }));
134
+ // Return cleanup function
135
+ return () => {
136
+ if (this.currentHandler === params) {
137
+ this.currentHandler = null;
138
+ }
139
+ };
140
+ }
141
+ catch (error) {
142
+ params.onError(error);
143
+ return () => { }; // No-op cleanup
144
+ }
145
+ }
146
+ /**
147
+ * Get chat history for a session
148
+ */
149
+ async getHistory(sessionId) {
150
+ const response = await fetch(`${this.baseUrl}/chat/history/${sessionId}`);
151
+ if (!response.ok) {
152
+ throw new Error(`Failed to get history: ${response.statusText}`);
153
+ }
154
+ return response.json();
155
+ }
156
+ /**
157
+ * Clear a chat session
158
+ */
159
+ async clearSession(sessionId) {
160
+ const response = await fetch(`${this.baseUrl}/chat/clear/${sessionId}`, {
161
+ method: "DELETE",
162
+ });
163
+ if (!response.ok) {
164
+ throw new Error(`Failed to clear session: ${response.statusText}`);
165
+ }
166
+ }
167
+ /**
168
+ * Health check
169
+ */
170
+ async health() {
171
+ const response = await fetch(`${this.baseUrl}/health`);
172
+ return response.json();
173
+ }
174
+ }
175
+ // Global instance
176
+ export const gojiClient = new GojiSearchClient(process.env.NEXT_PUBLIC_GOJI_API_URL || "http://localhost:8000");
@@ -0,0 +1 @@
1
+ @property --a{syntax: "<angle>"; inherits: true; initial-value: 0deg;}@property --l{syntax: "<number>"; inherits: true; initial-value: 0;}@property --x{syntax: "<length>"; inherits: false; initial-value: 0;}@property --y{syntax: "<length>"; inherits: false; initial-value: 0;}@property --o{syntax: "<number>"; inherits: false; initial-value: 0;}@property --value{syntax: "<angle>"; inherits: true; initial-value: 0deg;}@property --width-ratio{syntax: "<number>"; inherits: true; initial-value: 0;}@property --scale{syntax: "<number>"; inherits: true; initial-value: 0;}:root{--count: 4;--radius: .75rem;--width: .125rem;--duration: 8s}.ai{--s: 3.3rem;--p: calc(var(--s) / 4);width:var(--s);aspect-ratio:1;--bg-color: color-mix(in srgb, #7b7bf4, transparent 90%);background:radial-gradient(60% 75% at center,var(--bg-color) 50%,transparent 50%),radial-gradient(75% 60% at center,var(--bg-color) 50%,transparent 50%);padding:var(--p);display:grid;place-items:center;position:relative;border-radius:50%}@keyframes ai{0%{--a: 360deg;--l: .35;--o: 1}30%{--l: 1.5}70%{--o: .4;--l: .05}98%{--o: .7}to{--a: 0deg;--l: .35;--o: 1}}.c{opacity:.9;position:absolute;width:1.25rem;aspect-ratio:1;border-radius:50%;--offset-per-item: calc(360deg / var(--count));--current-angle-offset: calc(var(--offset-per-item) * var(--i) + var(--a));translate:calc(cos(var(--current-angle-offset)) * var(--radius) + var(--x, 0)) calc(sin(var(--current-angle-offset)) * var(--radius) * -1);scale:calc(.6 + var(--l));animation:ai 5.5s cubic-bezier(.45,-.35,.68,.24) infinite;transition:opacity .3s linear;opacity:var(--o, 1)}.c:nth-child(1){--i: 0}.c:nth-child(2){--i: 1}.c:nth-child(3){--i: 2}.c:nth-child(4){--i: 3}.c1{background:radial-gradient(50% 50% at center,#c979ee,#74bcd6);--x: .125rem;width:2rem;animation-timing-function:cubic-bezier(.12,.32,.68,.24)}.c2{background:radial-gradient(50% 50% at center,#ef788c,#e7e7fb);width:1.875rem}.c3{background:radial-gradient(50% 50% at center,#eb7fc6,transparent);width:.625rem;opacity:.6;--x: -.125rem}.c4{background:#6d67c8;animation-timing-function:cubic-bezier(.39,-.03,.75,.47)}.container-ai{overflow:hidden;background:#b6a9f8;width:100%;border-radius:50%;aspect-ratio:1;position:relative;display:grid;place-items:center}.glass-ai{overflow:hidden;position:absolute;--w: .0625rem;inset:calc(var(--p) - var(--w));border-radius:50%;-webkit-backdrop-filter:blur(.1625rem);backdrop-filter:blur(.1625rem);box-shadow:0 0 1rem color-mix(in srgb,black,transparent 70%);background:radial-gradient(1.25rem at 70% 30%,rgba(255,255,255,.7),transparent)}.glass-ai:after{content:"";position:absolute;inset:0;--c: rgba(255, 255, 255, .03);--w: .0625rem;--g: .1875rem;background:repeating-linear-gradient(var(--c),var(--c),var(--w),transparent var(--w),transparent calc(var(--w) + var(--g)));border-radius:inherit;border:.125rem rgba(255,255,255,.1) solid}.rings-ai{aspect-ratio:1;border-radius:50%;position:absolute;inset:0;perspective:11rem;opacity:.9}.rings-ai:before,.rings-ai:after{content:"";position:absolute;inset:0;background:red;border-radius:50%;--width-ratio: 1;border:calc(var(--width) * var(--width-ratio)) solid transparent;mask:linear-gradient(#fff 0 0) padding-box,linear-gradient(#fff 0 0);background:linear-gradient(#fff,#00f,#f0f,violet,#ffffe0) border-box;mask-composite:exclude;-webkit-mask-composite:xor;animation:ring-ai var(--duration) ease-in-out infinite;--start: 180deg;--value: var(--start);--scale: 1;transform:rotateY(var(--value)) rotateX(var(--value)) rotate(var(--value)) scale(var(--scale))}.rings-ai:before{--start: 180deg}.rings-ai:after{--start: 90deg}.rings-ai>.rings-ai:before{--start: 360deg}.rings-ai>.rings-ai:after{--start: 270deg}@keyframes ring-ai{0%{--value: var(--start);--scale: 1}50%{--scale: 1.2;--width-ratio: 1.5}70%{--scale: 1;--value: calc(var(--start) + 180deg);--width-ratio: 1}80%{--scale: 1.2;--width-ratio: 1.5}to{--value: calc(var(--start) + 360deg);--scale: 1;--width-ratio: 1}}@keyframes fadeIn{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes pulse{0%,to{opacity:.4}50%{opacity:1}}@keyframes slideUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUpMenu{0%{opacity:0;transform:translateY(12px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}
@@ -0,0 +1 @@
1
+ export { GojiSearchComponent } from './goji-search/components/goji-search-component';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ // Export React components for React users
2
+ export { GojiSearchComponent } from './goji-search/components/goji-search-component';
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "goji-search",
3
+ "version": "1.0.0",
4
+ "description": "Embeddable GojiSearch components for both React and vanilla JS",
5
+ "private": false,
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "module": "dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ }
18
+ },
19
+ "scripts": {
20
+ "dev": "vite",
21
+ "build": "tsc && vite build && npx tsc",
22
+ "dev-pack": "tsc && vite build && npx tsc && cp dist/goji-search.css dist/goji-search/components/goji-search.css && cp -r src/goji-search/assets dist/goji-search/ && npm pack",
23
+ "lint": "eslint ."
24
+ },
25
+ "peerDependencies": {
26
+ "react": "^18.0.0 || ^19.0.0",
27
+ "react-dom": "^18.0.0 || ^19.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@eslint/js": "^8.57.0",
31
+ "@types/node": "^20.12.0",
32
+ "@types/react": "^18.2.56",
33
+ "@types/react-dom": "^18.2.19",
34
+ "@vitejs/plugin-react": "^4.2.1",
35
+ "eslint": "^8.57.0",
36
+ "eslint-plugin-react-hooks": "^4.6.0",
37
+ "eslint-plugin-react-refresh": "^0.4.5",
38
+ "typescript": "^5.4.5",
39
+ "vite": "^7.1.9"
40
+ },
41
+ "dependencies": {
42
+ "@calcom/embed-react": "^1.5.3",
43
+ "lucide-react": "^0.545.0",
44
+ "react-markdown": "^10.1.0",
45
+ "remark-gfm": "^4.0.1"
46
+ }
47
+ }