Merge pull request #873 from ManishMadan2882/main

This commit is contained in:
Alex authored and GitHub committed 2024-03-07 19:26:33 +00:00
commit 4da400a136
5 files changed
+68 -55

No files matched your search

+1 -1
View File
@@ -7,7 +7,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vercel/analytics": "^1.1.1", "@vercel/analytics": "^1.1.1",
"docsgpt": "^0.3.0", "docsgpt": "^0.3.6",
"next": "^14.0.4", "next": "^14.0.4",
"nextra": "^2.13.2", "nextra": "^2.13.2",
"nextra-theme-docs": "^2.13.2", "nextra-theme-docs": "^2.13.2",
+12 -3
View File
@@ -10,7 +10,6 @@ First, make sure you have Node.js and npm installed in your project. Then go to
In the file where you want to use the widget, import it and include the CSS file: In the file where you want to use the widget, import it and include the CSS file:
```js ```js
import { DocsGPTWidget } from "docsgpt"; import { DocsGPTWidget } from "docsgpt";
import "docsgpt/dist/style.css";
``` ```
@@ -20,18 +19,28 @@ Now, you can use the widget in your component like this :
apiHost="https://your-docsgpt-api.com" apiHost="https://your-docsgpt-api.com"
selectDocs="local/docs.zip" selectDocs="local/docs.zip"
apiKey="" apiKey=""
avatar = "https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png",
title = "Get AI assistance",
description = "DocsGPT's AI Chatbot is here to help",
heroTitle = "Welcome to DocsGPT !",
heroDescription="This chatbot is built with DocsGPT and utilises GenAI,
please review important information using sources."
/> />
``` ```
DocsGPTWidget takes 3 **props**: DocsGPTWidget takes 8 **props** with default fallback values:
1. `apiHost` — The URL of your DocsGPT API. 1. `apiHost` — The URL of your DocsGPT API.
2. `selectDocs` — The documentation source that you want to use for your widget (e.g. `default` or `local/docs1.zip`). 2. `selectDocs` — The documentation source that you want to use for your widget (e.g. `default` or `local/docs1.zip`).
3. `apiKey` — Usually, it's empty. 3. `apiKey` — Usually, it's empty.
4. `avatar`: Specifies the URL of the avatar or image representing the chatbot.
5. `title`: Sets the title text displayed in the chatbot interface.
6. `description`: Provides a brief description of the chatbot's purpose or functionality.
7. `heroTitle`: Displays a welcome title when users interact with the chatbot.
8. `heroDescription`: Provide additional introductory text or information about the chatbot's capabilities.
### How to use DocsGPTWidget with [Nextra](https://nextra.site/) (Next.js + MDX) ### How to use DocsGPTWidget with [Nextra](https://nextra.site/) (Next.js + MDX)
Install your widget as described above and then go to your `pages/` folder and create a new file `_app.js` with the following content: Install your widget as described above and then go to your `pages/` folder and create a new file `_app.js` with the following content:
```js ```js
import { DocsGPTWidget } from "docsgpt"; import { DocsGPTWidget } from "docsgpt";
import "docsgpt/dist/style.css";
export default function MyApp({ Component, pageProps }) { export default function MyApp({ Component, pageProps }) {
return ( return (
+2 -2
View File
@@ -1,8 +1,8 @@
{ {
"name": "docsgpt", "name": "docsgpt",
"version": "0.3.0", "version": "0.3.6",
"private": false, "private": false,
"description": "docsgpt ai assistant", "description": "DocsGPT 🦖 is an innovative open-source tool designed to simplify the retrieval of information from project documentation using advanced GPT models 🤖.",
"source": "./src/index.html", "source": "./src/index.html",
"main": "dist/main.js", "main": "dist/main.js",
"module": "dist/module.js", "module": "dist/module.js",
@@ -1,12 +1,13 @@
"use client"; "use client";
import { Fragment, useEffect, useRef, useState } from 'react' import { Fragment, useEffect, useRef, useState } from 'react'
import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross1Icon } from '@radix-ui/react-icons'; import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross2Icon } from '@radix-ui/react-icons';
import { MESSAGE_TYPE } from '../models/types'; import { MESSAGE_TYPE } from '../models/types';
import { Query, Status } from '../models/types'; import { Query, Status } from '../models/types';
import MessageIcon from '../assets/message.svg' import MessageIcon from '../assets/message.svg'
import { fetchAnswerStreaming } from '../requests/streamingApi'; import { fetchAnswerStreaming } from '../requests/streamingApi';
import styled, { keyframes } from 'styled-components'; import styled, { keyframes } from 'styled-components';
const WidgetContainer = styled.div` const WidgetContainer = styled.div`
display: block;
position: fixed; position: fixed;
right: 10px; right: 10px;
bottom: 10px; bottom: 10px;
@@ -15,24 +16,25 @@ const WidgetContainer = styled.div`
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
text-align: left; text-align: left;
width: 356px;
height: 405px;
`; `;
const StyledContainer = styled.div` const StyledContainer = styled.div`
position: absolute; display: block;
position: relative;
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 352px;
height: 407px;
max-height: 407px;
border-radius: 0.75rem; border-radius: 0.75rem;
background-color: rgb(34, 35, 39); background-color: #222327;
border: 1px solid gray;
font-family: sans-serif; font-family: sans-serif;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1);
transition: visibility 0.3s, opacity 0.3s; transition: visibility 0.3s, opacity 0.3s;
`; `;
const FloatingButton = styled.div` const FloatingButton = styled.div`
position: absolute; position: fixed;
display: flex; display: flex;
z-index: 500;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
bottom: 1rem; bottom: 1rem;
@@ -61,8 +63,9 @@ const CancelButton = styled.button`
outline: none; outline: none;
color: inherit; color: inherit;
transition: opacity 0.3s ease; transition: opacity 0.3s ease;
opacity: 0.6;
&:hover { &:hover {
opacity: 0.5; opacity: 1;
} }
.white-filter { .white-filter {
filter: invert(100%); filter: invert(100%);
@@ -72,7 +75,9 @@ const CancelButton = styled.button`
const Header = styled.div` const Header = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0.75rem; padding-inline: 0.75rem;
padding-top: 1rem;
padding-bottom: 0.5rem;
`; `;
const IconWrapper = styled.div` const IconWrapper = styled.div`
@@ -98,8 +103,8 @@ const Description = styled.p`
margin-top: 0; margin-top: 0;
`; `;
const Conversation = styled.div` const Conversation = styled.div`
height: 18rem; height: 16rem;
padding: 0.5rem; padding-inline: 0.5rem;
border-radius: 0.375rem; border-radius: 0.375rem;
text-align: left; text-align: left;
overflow-y: auto; overflow-y: auto;
@@ -109,19 +114,19 @@ const Conversation = styled.div`
const MessageBubble = styled.div<{ type: MESSAGE_TYPE }>` const MessageBubble = styled.div<{ type: MESSAGE_TYPE }>`
display: flex; display: flex;
font-size: 16px;
justify-content: ${props => props.type === 'QUESTION' ? 'flex-end' : 'flex-start'}; justify-content: ${props => props.type === 'QUESTION' ? 'flex-end' : 'flex-start'};
margin: 0.5rem; margin: 0.5rem;
`; `;
const Message = styled.p<{ type: MESSAGE_TYPE }>` const Message = styled.p<{ type: MESSAGE_TYPE }>`
background: ${props => props.type === 'QUESTION' ? background: ${props => props.type === 'QUESTION' ?
'linear-gradient(to bottom right, #8860DB, #6D42C5)' : 'linear-gradient(to bottom right, #8860DB, #6D42C5)' :
props => props.type === 'ANSWER' ? '#38383b'};
'#38383b' : color: #ffff;
''}; border: none;
color: ${props => props.type != 'ERROR' ? '#ffff' : '#b91c1c'};
border:${props => props.type !== 'ERROR' ? 'none' : '1px solid #b91c1c'};
max-width: 80%; max-width: 80%;
margin: 4px;
display: block; display: block;
padding: 0.75rem; padding: 0.75rem;
border-radius: 0.375rem; border-radius: 0.375rem;
@@ -151,21 +156,23 @@ const DotAnimation = styled.div`
display: inline-block; display: inline-block;
animation: ${dotBounce} 1s infinite ease-in-out; animation: ${dotBounce} 1s infinite ease-in-out;
`; `;
// delay classes as styled components // delay classes as styled components
const Delay = styled(DotAnimation) <{ delay: number }>` const Delay = styled(DotAnimation) <{ delay: number }>`
animation-delay: ${props => props.delay + 'ms'}; animation-delay: ${props => props.delay + 'ms'};
`; `;
const PromptContainer = styled.form` const PromptContainer = styled.form`
background-color: transparent; background-color: transparent;
padding: 12px 8px; height: 36px;
opacity: 1; position: absolute;
height: 40px; bottom: 25px;
left: 24px;
right: 24px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-evenly;
`; `;
const StyledInput = styled.input` const StyledInput = styled.input`
width: 80%; width: 260px;
height: 36px;
border: 1px solid #686877; border: 1px solid #686877;
padding-left: 12px; padding-left: 12px;
background-color: transparent; background-color: transparent;
@@ -175,19 +182,24 @@ const StyledInput = styled.input`
outline: none; outline: none;
`; `;
const StyledButton = styled.button` const StyledButton = styled.button`
color: #ccc; display: flex;
justify-content: center;
align-items: center;
background-image: linear-gradient(to bottom right, #5AF0EC, #E80D9D); background-image: linear-gradient(to bottom right, #5AF0EC, #E80D9D);
border-radius: 6px; border-radius: 6px;
width: 40px; width: 36px;
height: 36px;
margin-left:8px;
padding: 0px;
border: none; border: none;
cursor: pointer; cursor: pointer;
outline: none; outline: none;
&:hover{ &:hover{
opacity: 80%; opacity: 90%;
} }
&:disabled { &:disabled {
opacity: 60%; opacity: 60%;
}` }`;
const HeroContainer = styled.div` const HeroContainer = styled.div`
position: absolute; position: absolute;
top: 50%; top: 50%;
@@ -208,7 +220,6 @@ const HeroWrapper = styled.div`
font-weight: normal; font-weight: normal;
padding: 6px; padding: 6px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
` `
const HeroTitle = styled.h3` const HeroTitle = styled.h3`
@@ -217,16 +228,12 @@ const HeroTitle = styled.h3`
margin-bottom: 5px; margin-bottom: 5px;
padding: 2px; padding: 2px;
`; `;
const HeroDescription = styled.p` const HeroDescription = styled.p`
color: #fff; color: #fff;
font-size: 14px; font-size: 14px;
line-height: 1.5; line-height: 1.5;
`; `;
const Avatar = styled.img<{width:number,height:number}>` const Hero = ({ title, description }: { title: string, description: string }) => {
max-width: ${props => props.width};
`
const Hero = ({title,description}:{title:string,description:string}) => {
return ( return (
<> <>
<HeroContainer> <HeroContainer>
@@ -247,13 +254,13 @@ const Hero = ({title,description}:{title:string,description:string}) => {
}; };
export const DocsGPTWidget = ({ export const DocsGPTWidget = ({
apiHost = 'https://gptcloud.arc53.com', apiHost = 'https://gptcloud.arc53.com',
selectDocs = 'default', selectDocs = 'default',
apiKey = 'docsgpt-public', apiKey = 'docsgpt-public',
avatar = 'https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png', avatar = 'https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png',
title = 'Get AI assistance', title = 'Get AI assistance',
description = 'DocsGPT\'s AI Chatbot is here to help', description = 'DocsGPT\'s AI Chatbot is here to help',
heroTitle = 'Welcome to DocsGPT !', heroTitle = 'Welcome to DocsGPT !',
heroDescription='This chatbot is built with DocsGPT and utilises GenAI, please review important information using sources.' heroDescription = 'This chatbot is built with DocsGPT and utilises GenAI, please review important information using sources.'
}) => { }) => {
const [prompt, setPrompt] = useState(''); const [prompt, setPrompt] = useState('');
@@ -334,17 +341,17 @@ export const DocsGPTWidget = ({
return ( return (
<> <>
<WidgetContainer> <WidgetContainer>
<FloatingButton onClick={() => setOpen(true)} hidden={open}> {!open && <FloatingButton onClick={() => setOpen(true)} hidden={open}>
<MessageIcon style={{marginTop:'8px'}}/> <MessageIcon style={{ marginTop: '8px' }} />
</FloatingButton> </FloatingButton>}
{open && <StyledContainer> {open && <StyledContainer>
<div> <div>
<CancelButton onClick={() => setOpen(false)}> <CancelButton onClick={() => setOpen(false)}>
<Cross1Icon width={20} height={20} color='white'/> <Cross2Icon width={24} height={24} color='white'/>
</CancelButton> </CancelButton>
<Header> <Header>
<IconWrapper> <IconWrapper>
<img style={{maxWidth:"42px",maxHeight:"42px"}} onError={handleImageError} src={avatar} alt='docs-gpt' /> <img style={{ maxWidth: "42px", maxHeight: "42px" }} onError={handleImageError} src={avatar} alt='docs-gpt' />
</IconWrapper> </IconWrapper>
<ContentWrapper> <ContentWrapper>
<Title>{title}</Title> <Title>{title}</Title>
@@ -352,7 +359,6 @@ export const DocsGPTWidget = ({
</ContentWrapper> </ContentWrapper>
</Header> </Header>
</div> </div>
<div style={{ width: '100%' }}>
<Conversation> <Conversation>
{ {
queries.length > 0 ? queries?.map((query, index) => { queries.length > 0 ? queries?.map((query, index) => {
@@ -399,22 +405,20 @@ export const DocsGPTWidget = ({
} }
</Fragment>) </Fragment>)
}) })
: <Hero title={heroTitle} description={heroDescription}/> : <Hero title={heroTitle} description={heroDescription} />
} }
</Conversation> </Conversation>
<PromptContainer
<PromptContainer
onSubmit={handleSubmit}> onSubmit={handleSubmit}>
<StyledInput <StyledInput
value={prompt} onChange={(event) => setPrompt(event.target.value)} value={prompt} onChange={(event) => setPrompt(event.target.value)}
type='text' placeholder="What do you want to do?" /> type='text' placeholder="What do you want to do?" />
<StyledButton <StyledButton
disabled={prompt.length == 0 || status !== 'idle'}> disabled={prompt.length == 0 || status !== 'idle'}>
<PaperPlaneIcon color='white' /> <PaperPlaneIcon width={15} height={15} color='white' />
</StyledButton> </StyledButton>
</PromptContainer> </PromptContainer>
</div>
</StyledContainer>} </StyledContainer>}
</WidgetContainer> </WidgetContainer>
</> </>
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React (Parcel + TypeScript)</title> <title>DocsGPT Widget</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>