Skip to content

Commit

Permalink
Add GPT Chat to Base Docs (#323)
Browse files Browse the repository at this point in the history
* Install fetch event source to handle SSEs

* Add docs chatbot modal UI.

* Update Modal and Icon components.

* Add no scroll class.

* Add DocChat component.

* Installed fetch event source.

* Add light theme styles. Clean up code.

* Remove unneeded React import.

* Adjust copy as deployment test change.

* Undo test changes.

* Add Mendable URLs to CSP.

* Add markdown rendering support for chatbot responses.

* Yarn lock update.

* Adjust modal layout spacing.

* Fix chatbot modal styling for mobile screens.

* Add UI for rating bot responses.

* Temporarily disable response rating feature.

* Add server API endpoint for processing Base GPT response rating requests.

* Update csp for new API version.

* Add CCA events for GPT interactions. Fix id data types.

* Swap in prod client-side API keys.

* Use session storage for conversation data.

* Swap in prod client-side API keys.

* Remove unneeded log.

* Simplify state updates.

* Replace dangerouslySetInnerHTML with useRef innerHTML.

* Updated yarn.lock

* Swap in test API key for dev.

* Fix typo.

* Swap in prod client-side key.

* Temporarily remove sources. Adjust scroll behavior. Adjust modal close handler. Update API keys.
  • Loading branch information
jacob-moore-cb authored Mar 7, 2024
1 parent 691cfab commit 8fbeb79
Show file tree
Hide file tree
Showing 24 changed files with 1,469 additions and 18 deletions.
1 change: 1 addition & 0 deletions apps/base-docs/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MENDABLE_SERVER_API_KEY=
1 change: 1 addition & 0 deletions apps/base-docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
4 changes: 2 additions & 2 deletions apps/base-docs/docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ Get the EVM environment at a fraction of the cost. Get early access to Ethereum

### Open source

Base is built on the MIT-licensed [OP Stack](https://stack.optimism.io/), in collaboration with Optimism. Were joining as the second Core Dev team working on the OP Stack to ensure it’s a public good available to everyone.
Base is built on the MIT-licensed [OP Stack](https://stack.optimism.io/), in collaboration with Optimism. We're joining as the second Core Dev team working on the OP Stack to ensure it’s a public good available to everyone.

### Scaled by Coinbase

Base is an easy way for decentralized apps to leverage Coinbases products and distribution. Seamless Coinbase integrations, easy fiat onramps, and access to millions of verified users in the Coinbase ecosystem.
Base is an easy way for decentralized apps to leverage Coinbase's products and distribution. Seamless Coinbase integrations, easy fiat onramps, and access to millions of verified users in the Coinbase ecosystem.
5 changes: 4 additions & 1 deletion apps/base-docs/docusaurus.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,14 @@ enum AnalyticsEventImportance {
type CCAEventData = {
// Standard Attributes
action: ActionType;
componentType: ComponentType;
component_type: ComponentType;
// Custom Attributes
doc_helpful?: boolean;
doc_feedback_reason?: string | null;
page_path?: string;
conversation_id?: number;
message_id?: number;
response_helpful?: boolean;
};

export type LogEvent = (
Expand Down
6 changes: 6 additions & 0 deletions apps/base-docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@
"@docusaurus/core": "2.4.1",
"@docusaurus/preset-classic": "2.4.1",
"@mdx-js/react": "^1.6.22",
"@microsoft/fetch-event-source": "^2.0.1",
"@rainbow-me/rainbowkit": "^1.0.4",
"@types/dompurify": "^3.0.5",
"body-parser": "^1.20.2",
"docusaurus-node-polyfills": "^1.0.0",
"dompurify": "^3.0.8",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-basic-auth": "^1.2.1",
"lodash": "^4.17.21",
"marked": "^11.1.1",
"node-fetch": "2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.1.3",
Expand Down
30 changes: 30 additions & 0 deletions apps/base-docs/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ const path = require('path');
const basicAuth = require('express-basic-auth');
const fs = require('fs');
const notFound = require('./404.js');
const bodyParser = require('body-parser');
const fetch = require('node-fetch');
const dotenv = require('dotenv');

dotenv.config();

const unless = function (path, middleware) {
return function (req, res, next) {
Expand All @@ -18,10 +23,32 @@ const app = express();

app.use(express.static('static'));

app.use(bodyParser.json());

app.get('/api/_health', (_, res) => {
res.sendStatus(200);
});

app.post('/api/rateMessage', (req, res) => {
const { message_id, rating_value } = req.body;

const data = {
api_key: process.env.MENDABLE_SERVER_API_KEY,
message_id,
rating_value,
};

fetch('https://api.mendable.ai/v1/rateMessage', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then((response) => res.json(response))
.catch((error) => res.status(400));
});

app.get('/base-camp', (req, res) => {
res.redirect('base-camp/docs/welcome');
});
Expand Down Expand Up @@ -73,6 +100,9 @@ const contentSecurityPolicy = {
'https://cca-lite.coinbase.com', // CCA Lite
'https://*.algolia.net', // Algolia Search
'https://*.algolianet.com', // Algolia Search
'https://api.mendable.ai/v1/newConversation', // Mendable API
'https://api.mendable.ai/v1/mendableChat', // Mendable API
'https://api.mendable.ai/v1/rateMessage', // Mendable API
],
'frame-src': ["'self'", 'https://player.vimeo.com', 'https://verify.walletconnect.org'],
};
Expand Down
92 changes: 92 additions & 0 deletions apps/base-docs/src/components/DocChat/ChatMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React, { useRef, useLayoutEffect } from 'react';
import { parseMarkdown } from '../../utils/marked';

import Icon from '../Icon';
import ResponseFeedback from './ResponseFeedback';
// import ResponseSource from './ResponseSource';

import styles from './styles.module.css';

import { ConversationMessage } from './docChat';

type ChatMessageProps = {
index: number;
type: ConversationMessage['type'];
content: ConversationMessage['content'];
sources?: ConversationMessage['sources'];
messageId?: number;
conversationId: number;
conversation: ConversationMessage[];
setConversation: (
conversation: (prevState: ConversationMessage[]) => ConversationMessage[],
) => void;
};

export default function ChatMessage({
index,
messageId,
conversationId,
conversation,
setConversation,
type,
content,
sources,
}: ChatMessageProps) {
const responseContentRef = useRef<HTMLDivElement>(null);

useLayoutEffect(() => {
if (responseContentRef.current) {
responseContentRef.current.innerHTML = parseMarkdown(content);
}
}, [content]);

return (
<div className={styles.chatMessageContainer}>
<div className={styles.chatMessage}>
{type === 'prompt' && content !== '' && (
<>
<div className={styles.chatMessageIcon}>
<Icon name="avatar" width="24" height="24" />
</div>
<div>{content}</div>
</>
)}

{type === 'response' && content !== '' && (
<>
<div className={styles.chatMessageIcon}>
<Icon name="base-logo" width="24" height="24" />
</div>
<div ref={responseContentRef} className={styles.chatMessageContent} />
</>
)}
</div>

{sources && sources.length > 0 && (
<>
<ResponseFeedback
responseIndex={index}
messageId={messageId}
conversationId={conversationId}
conversation={conversation}
setConversation={setConversation}
/>

{/* Source data provided by the Mendable API needs more tuning but will be supported in a future release */}
{/* <div className={styles.chatMessageSourcesLabel}>Verified Sources:</div>
<div className={styles.chatMessageSourcesContainer}>
{sources.map((source, i) => (
<ResponseSource
key={source}
index={i}
conversationId={conversationId}
messageId={messageId}
source={source}
/>
))}
</div> */}
</>
)}
</div>
);
}
Loading

0 comments on commit 8fbeb79

Please sign in to comment.