-
Notifications
You must be signed in to change notification settings - Fork 102
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: chat widget for DocsGPT (#606)
* feat: demo of DocsGPTChatWidget has been verified * add message loading animation & freeze input when waiting for answer * check if docs is availabel for the current repo * add prompts for requesting for new docs * also powered by X-lab * handle repo switching * support history & fix bugs * add custom styles * support Dark and Light themes * support to enable/disable the feature * update issue link * tell users that the feature can be toggled * workaround to change emoji picker color * disable emoji
- Loading branch information
Showing
11 changed files
with
1,423 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import React from 'react'; | ||
import { render } from 'react-dom'; | ||
import $ from 'jquery'; | ||
import { utils } from 'github-url-detection'; | ||
|
||
import PerceptorBase from '../PerceptorBase'; | ||
import { runsWhen, isPublicRepo, getGithubTheme } from '../utils/utils'; | ||
import DocsGPTChatWidget from '../views/DocsGPTChatWidget'; | ||
|
||
const DOCS_META_DATA_URL = | ||
'https://oss.x-lab.info/hypercrx/docsgpt_active_docs.json'; | ||
|
||
interface DocsMetaItem { | ||
type: 'repo' | 'org'; | ||
name: string; // GitHub repo name or org name | ||
key: string; // corresponding docs name | ||
} | ||
|
||
@runsWhen([isPublicRepo]) | ||
class DocsGPTChatWidgetAnchor extends PerceptorBase { | ||
private _currentRepo: string; | ||
private _docsMetaData: DocsMetaItem[]; | ||
|
||
constructor() { | ||
super(); | ||
this._currentRepo = ''; | ||
this._docsMetaData = []; | ||
} | ||
|
||
private async _getDocsMetaData() { | ||
const response = await fetch(DOCS_META_DATA_URL); | ||
if (response.ok) { | ||
this._docsMetaData = await response.json(); | ||
} else { | ||
throw new Error('Failed to fetch docs meta data'); | ||
} | ||
} | ||
|
||
private get _currentDocsName(): string | null { | ||
const orgName = this._currentRepo.split('/')[0]; | ||
let result = null; | ||
for (const item of this._docsMetaData) { | ||
if (item.type === 'repo' && item.name === this._currentRepo) { | ||
result = item.key; | ||
break; | ||
} else if (item.type === 'org' && item.name === orgName) { | ||
result = item.key; | ||
break; | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
public async run(): Promise<void> { | ||
const repoName = utils.getRepositoryInfo(window.location)!.nameWithOwner; | ||
|
||
if ($('#docs-gpt-chat-widget').length !== 0) { | ||
if ($('#docs-gpt-chat-widget').data('repo') === repoName) { | ||
return; // should not re-render for same repo | ||
} else { | ||
$('#docs-gpt-chat-widget').remove(); | ||
} | ||
} | ||
|
||
this._currentRepo = repoName; | ||
await this._getDocsMetaData(); | ||
|
||
const container = document.createElement('div'); | ||
container.id = 'docs-gpt-chat-widget'; | ||
container.className = getGithubTheme()!; | ||
container.dataset.repo = this._currentRepo; // mark current repo by data-repo | ||
render( | ||
<DocsGPTChatWidget | ||
currentRepo={this._currentRepo} | ||
currentDocsName={this._currentDocsName} | ||
/>, | ||
container | ||
); | ||
$('body').append(container); | ||
} | ||
} | ||
|
||
export default DocsGPTChatWidgetAnchor; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import { | ||
Widget, | ||
addResponseMessage, | ||
deleteMessages, | ||
toggleMsgLoader, | ||
toggleInputDisabled, | ||
} from 'react-chat-widget'; | ||
|
||
import { getAnswer } from './service'; | ||
import './rcw.scss'; | ||
|
||
interface Props { | ||
currentRepo: string; | ||
currentDocsName: string | null; | ||
} | ||
|
||
const displayWelcome = (repoName: string) => { | ||
addResponseMessage( | ||
`Hi, I'm an assistant powered by [DocsGPT](https://github.com/arc53/docsgpt) and [X-lab](https://github.com/X-lab2017). Ask me anything about \`${repoName}\`!` | ||
); | ||
}; | ||
|
||
const displayNotAvailable = (repoName: string) => { | ||
addResponseMessage( | ||
`OSS-GPT currently is **NOT AVAILABLE** for \`${repoName}\`. If you want docs support for the repository, please check [this](https://github.com/hypertrons/hypertrons-crx/issues/609) issue and make a request there :)\n\nSee [all available docs](https://oss.x-lab.info/hypercrx/docsgpt_active_docs.json)\n\nThis chat widget can also be enable/disabled in the extension options page whenever you want.` | ||
); | ||
}; | ||
|
||
const View = ({ currentRepo, currentDocsName }: Props): JSX.Element => { | ||
const subtitle = currentDocsName | ||
? `Ask anything about ${currentRepo}` | ||
: `NOT AVAILABLE for ${currentRepo}`; | ||
|
||
const [history, setHistory] = useState<[string, string]>(['', '']); | ||
|
||
const handleNewUserMessage = async (newMessage: string) => { | ||
toggleMsgLoader(); | ||
toggleInputDisabled(); | ||
|
||
if (currentDocsName) { | ||
const answer = await getAnswer(currentDocsName, newMessage, history); | ||
addResponseMessage(answer); | ||
setHistory([newMessage, answer]); // update history | ||
} else { | ||
displayNotAvailable(currentRepo); | ||
} | ||
|
||
toggleMsgLoader(); | ||
toggleInputDisabled(); | ||
}; | ||
|
||
useEffect(() => { | ||
// when repo changes | ||
deleteMessages(Infinity); // delete all messages after repo switching | ||
setHistory(['', '']); // clear history | ||
if (currentDocsName) { | ||
// if docs for current repo is available | ||
displayWelcome(currentRepo); | ||
} else { | ||
displayNotAvailable(currentRepo); | ||
} | ||
}, [currentRepo, currentDocsName]); | ||
|
||
return ( | ||
<Widget | ||
title="OSS-GPT" | ||
subtitle={subtitle} | ||
emojis={false} // will be enabled after style is fine tuned for two themes | ||
resizable={true} | ||
handleNewUserMessage={handleNewUserMessage} | ||
/> | ||
); | ||
}; | ||
|
||
export default View; |
Oops, something went wrong.