"use client"; import {useEffect, useRef, useState} from 'react' //import './style.css' interface HistoryItem { prompt: string; response: string; } interface FetchAnswerStreamingProps { question?: string; apiKey?: string; selectedDocs?: string; history?: HistoryItem[]; conversationId?: string | null; apiHost?: string; onEvent?: (event: MessageEvent) => void; } enum ChatStates { Init = 'init', Processing = 'processing', Typing = 'typing', Answer = 'answer', Minimized = 'minimized', } function fetchAnswerStreaming({ question = '', apiKey = '', selectedDocs = '', history = [], conversationId = null, apiHost = '', onEvent = () => {console.log("Event triggered, but no handler provided.");} }: FetchAnswerStreamingProps): Promise { let docPath = 'default'; if (selectedDocs) { docPath = selectedDocs; } return new Promise((resolve, reject) => { const body = { question: question, api_key: apiKey, embeddings_key: apiKey, active_docs: docPath, history: JSON.stringify(history), conversation_id: conversationId, model: 'default' }; fetch(apiHost + '/stream', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body), }) .then((response) => { if (!response.body) throw Error('No response body'); const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); let counterrr = 0; const processStream = ({ done, value, }: ReadableStreamReadResult) => { if (done) { console.log(counterrr); resolve(); return; } counterrr += 1; const chunk = decoder.decode(value); const lines = chunk.split('\n'); for (let line of lines) { if (line.trim() == '') { continue; } if (line.startsWith('data:')) { line = line.substring(5); } const messageEvent = new MessageEvent('message', { data: line, }); onEvent(messageEvent); // handle each message } reader.read().then(processStream).catch(reject); }; reader.read().then(processStream).catch(reject); }) .catch((error) => { console.error('Connection failed:', error); reject(error); }); }); } export const DocsGPTWidget = ({ apiHost = 'https://gptcloud.arc53.com', selectDocs = 'default', apiKey = 'docsgpt-public'}) => { // processing states const [chatState, setChatState] = useState(() => { if (typeof window !== 'undefined') { return localStorage.getItem('docsGPTChatState') as ChatStates || ChatStates.Init; } return ChatStates.Init; }); const [answer, setAnswer] = useState(''); //const selectDocs = 'local/1706.03762.pdf/' const answerRef = useRef(null); useEffect(() => { if (answerRef.current) { const element = answerRef.current; element.scrollTop = element.scrollHeight; } }, [answer]); useEffect(() => { if (chatState === ChatStates.Init || chatState === ChatStates.Minimized) { localStorage.setItem('docsGPTChatState', chatState); } }, [chatState]); // submit handler const handleSubmit = (e: React.FormEvent) => { setAnswer('') e.preventDefault() // get question setChatState(ChatStates.Processing) setTimeout(() => { setChatState(ChatStates.Answer) }, 800) const inputElement = e.currentTarget[0] as HTMLInputElement; const questionValue = inputElement.value; fetchAnswerStreaming({ question: questionValue, apiKey: apiKey, selectedDocs: selectDocs, history: [], conversationId: null, apiHost: apiHost, onEvent: (event) => { const data = JSON.parse(event.data); // check if the 'end' event has been received if (data.type === 'end') { setChatState(ChatStates.Answer) } else if (data.type === 'source') { // check if data.metadata exists let result; if (data.metadata && data.metadata.title) { const titleParts = data.metadata.title.split('/'); result = { title: titleParts[titleParts.length - 1], text: data.doc, }; } else { result = { title: data.doc, text: data.doc }; } console.log(result) } else if (data.type === 'id') { console.log(data.id); } else { const result = data.answer; // set answer by appending answer setAnswer(prevAnswer => prevAnswer + result); } }, }); } return ( <>
setChatState(ChatStates.Init)} className={`${chatState !== 'minimized' ? 'hidden' : ''} cursor-pointer`}>
DocsGPT
Exit { event.stopPropagation(); setChatState(ChatStates.Minimized); }} />

Looking for help with documentation?

DocsGPT AI assistant will help you with docs

{answer}

{ (chatState === 'typing' || chatState === 'answer') && (
)}

Processing...

) }