Skip to content

Commit

Permalink
support chatgpt web
Browse files Browse the repository at this point in the history
  • Loading branch information
anc95 committed Jul 6, 2023
1 parent ee1a254 commit bdcd2cb
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 24 deletions.
29 changes: 25 additions & 4 deletions src/background/chatgpt-web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ browser.runtime.onConnect.addListener((port) => {
port.onMessage.addListener((msg) => {
if (msg.type === EventName.chat) {
sendMessageOnChatGPTWeb(msg.data, port)
} else if (msg.type === EventName.stopChatGPTChat) {
abortController.abort()
}
})
})
Expand All @@ -25,41 +27,60 @@ browser.runtime.onMessage.addListener(
}
)

let conversation_id = undefined
let parent_message_id = uuidv4()
let abortController = new AbortController()

const sendMessageOnChatGPTWeb = async (prompt: string, port) => {
const token = await getAccessToken()
const msgUUID = uuidv4()
abortController.abort()
abortController = new AbortController()

const res = await fetch('https://chat.openai.com/backend-api/conversation', {
method: 'POST',
body: JSON.stringify({
action: 'next',
messages: [
{
id: uuidv4(),
id: msgUUID,
author: { role: 'user' },
content: { content_type: 'text', parts: [prompt] },
metadata: {},
},
],
model: 'text-davinci-002-render-sha',
parent_message_id: uuidv4(),
parent_message_id: parent_message_id,
conversation_id: conversation_id,
}),
headers: {
Accept: 'text/event-stream',
Authorization: `Bearer ${token}`,
'content-type': 'application/json',
},
signal: abortController.signal,
})

parent_message_id = msgUUID

const reader = res.body.getReader()
return new ReadableStream({
start(controller) {
return pump()
function pump() {
return reader.read().then(({ done, value }) => {
console.log(new TextDecoder().decode(value))
const strValue = new TextDecoder().decode(value)
const cId = /"conversation_id":\s+"([^"]+)+/.exec(strValue)?.[1]

if (cId) {
conversation_id = cId
}

console.log('发送消息', port)

port?.postMessage({
type: EventName.chatgptResponse,
data: new TextDecoder().decode(value),
data: strValue,
})

if (done) {
Expand Down
5 changes: 3 additions & 2 deletions src/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ browser.runtime.onMessage.addListener(
browser.contextMenus.create({
title: 'Launch writely',
id: 'writely',
contexts: ['selection'],
// contexts: ['selection'],
})

browser.contextMenus.create({
title: 'Writely instructions',
id: 'writely-instructions',
contexts: ['selection'],
// contexts: ['selection'],
})

const createSubMenu = async () => {
Expand All @@ -49,6 +49,7 @@ const createSubMenu = async () => {
createSubMenu()

browser.contextMenus.onClicked.addListener((info, tab) => {
console.error('hi')
if (info.menuItemId === 'writely' && tab.id) {
browser.tabs.sendMessage(tab.id, {
type: EventName.launchWritely,
Expand Down
6 changes: 6 additions & 0 deletions src/common/api/chatgpt-web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ class ChatGPTWeb {
})
}

public abort = () => {
this.port.postMessage({
type: EventName.stopChatGPTChat,
})
}

private initToken = async () => {
this.accessToken = await Browser.runtime.sendMessage({
type: EventName.getChatGPTToken,
Expand Down
4 changes: 3 additions & 1 deletion src/common/api/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ export const useQueryOpenAIPrompt = () => {

if (settings.serviceProvider === ServiceProvider.ChatGPT) {
chatgptWeb.sendMsg(prompt, onData)

return chatgptWeb.abort
} else if (isChat) {
openAI?.current?.createChatCompletion(
{
Expand Down Expand Up @@ -129,7 +131,7 @@ export const useOpenAIEditPrompt = () => {
if (
(settings.model !== 'text-davinci-edit-001' &&
settings.model !== 'code-davinci-edit-001') ||
settings.serviceProvider === ServiceProvider.Writely
settings.serviceProvider !== ServiceProvider.OpenAI
) {
return queryPrompt(
!instruction
Expand Down
1 change: 1 addition & 0 deletions src/common/event-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum EventName {
chat = 'chat',
chatgptResponse = 'chatgpt-response',
getChatGPTToken = 'get-chatgpt-token',
stopChatGPTChat = 'stop-chatgpt-chat',
}

export enum PortName {
Expand Down
1 change: 1 addition & 0 deletions src/common/parse-stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const parseStream = (content: string) => {
if (text.length > result.length) {
result = text
}
console.log(text, '=======', result)
} else {
result += text
}
Expand Down
12 changes: 7 additions & 5 deletions src/content/container/ask-writely/result-panel/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import { chatgptWeb } from '@/common/api/chatgpt-web'

const md = mdit().use(hljsPlugin)

export const Content: React.FC<{ text: string }> = ({ text: task }) => {
export const Content: React.FC<{
text: string
abortRef: MutableRefObject<() => void>
}> = ({ text: task, abortRef }) => {
const mdContainerRef = useRef<HTMLDivElement>()
const selectionManager = useSelectionManager()
const queryOpenAIPrompt = useOpenAIEditPrompt()
Expand All @@ -40,7 +43,6 @@ export const Content: React.FC<{ text: string }> = ({ text: task }) => {
const { settings } = useSettings()
const sequenceRef = useRef<number>(0)
const { isOriginText } = useResultPanel()
const abortRef = useRef<() => void>(null)

const handleQuery = useCallback(async () => {
if (!selectionManager.text) {
Expand Down Expand Up @@ -118,10 +120,10 @@ export const Content: React.FC<{ text: string }> = ({ text: task }) => {
}

return (
<div className="shadow-xl bg-zinc-100">
<div className="shadow-xl bg-zinc-100 relative">
<div className="p-4 max-h-[50vh] overflow-auto transition-all duration-700">
{loading ? (
<div className="flex justify-center text-xl">
<div className="flex justify-center text-xl sticky top-0">
<StopGenerate
onClick={() => {
abortRef?.current?.()
Expand Down Expand Up @@ -154,7 +156,7 @@ export const Content: React.FC<{ text: string }> = ({ text: task }) => {

const StopGenerate: React.FC<{ onClick?: () => void }> = ({ onClick }) => {
return (
<div className="w-fit">
<div className="w-fit rounded-3xl bg-slate-100">
<Tooltip title={i18next.t('##Stop Generate')} trigger="hover">
<IconBtn
color="red"
Expand Down
13 changes: 10 additions & 3 deletions src/content/container/ask-writely/result-panel/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,32 @@ import {
DashiconsAdminGeneric,
RiHeartFill,
} from '@/components/icon'
import { ReactNode } from 'react'
import { MutableRefObject, ReactNode } from 'react'
import { useView } from '../../store/view'
import i18next from 'i18next'
import { useResultPanel } from '../../store/result-panel'
import type { MessagePayload } from '@/common/types'
import { EventName } from '@/common/event-name'
import browser from 'webextension-polyfill'

export const Header: React.FC = () => {
export const Header: React.FC<{ abortRef: MutableRefObject<() => void> }> = ({
abortRef,
}) => {
const { hide, goToInputPage } = useView()
const { isOriginText, setIsOriginText } = useResultPanel()

const back = () => {
goToInputPage()
abortRef.current?.()
}

return (
<div className="flex px-2 items-center bg-zinc-900 cursor-move handle justify-between">
<div className="flex items-center">
<Operation
icon={<MaterialSymbolsKeyboardBackspace />}
tooltip="Back"
onClick={goToInputPage}
onClick={back}
/>
<Operation icon={<MdiClose />} tooltip="Close window" onClick={hide} />
</div>
Expand Down
19 changes: 11 additions & 8 deletions src/content/container/ask-writely/result-panel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { ResultPanelProvider } from '../../store/result-panel';
import { Content } from './content';
import { Header } from './header';
import { useRef } from 'react'
import { ResultPanelProvider } from '../../store/result-panel'
import { Content } from './content'
import { Header } from './header'

export const ResultPanel: React.FC<{
text: string;
text: string
}> = ({ text }) => {
const abortRef = useRef<() => void>(() => {})

return (
<ResultPanelProvider>
<div className="overflow-hidden rounded-lg shadow-xl w-[500px]">
<div className="border-zinc-200 rounded-lg">
<Header />
<Header abortRef={abortRef} />
</div>
<Content text={text} />
<Content text={text} abortRef={abortRef} />
</div>
</ResultPanelProvider>
);
};
)
}
3 changes: 2 additions & 1 deletion src/content/container/store/result-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const { useContainer: useResultPanel, Provider: ResultPanelProvider } =
setIsOriginText,
setText: useCallback((newText: string) => {
setText((value) => {
if (newText.length > value.length) {
// ChatGPT web last stream is empty
if (newText.trim()?.length) {
return newText
}

Expand Down

0 comments on commit bdcd2cb

Please sign in to comment.