Skip to content

Commit 48c2618

Browse files
committed
feat: stop generating answers
1 parent c6caf56 commit 48c2618

File tree

7 files changed

+79
-9
lines changed

7 files changed

+79
-9
lines changed

src/background/apis/chatgpt-web.mjs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,24 @@ export async function generateAnswersWithChatgptWebApi(port, question, session,
5353
}
5454

5555
const controller = new AbortController()
56+
const stopListener = (msg) => {
57+
if (msg.stop) {
58+
console.debug('stop generating')
59+
port.postMessage({ done: true })
60+
controller.abort()
61+
port.onMessage.removeListener(stopListener)
62+
}
63+
}
64+
port.onMessage.addListener(stopListener)
5665
port.onDisconnect.addListener(() => {
5766
console.debug('port disconnected')
5867
controller.abort()
5968
deleteConversation()
6069
})
6170

62-
const models = await getModels(accessToken).catch(() => {})
71+
const models = await getModels(accessToken).catch(() => {
72+
port.onMessage.removeListener(stopListener)
73+
})
6374
const config = await getUserConfig()
6475

6576
let answer = ''
@@ -112,8 +123,12 @@ export async function generateAnswersWithChatgptWebApi(port, question, session,
112123
async onStart() {
113124
// sendModerations(accessToken, question, session.conversationId, session.messageId)
114125
},
115-
async onEnd() {},
126+
async onEnd() {
127+
port.onMessage.removeListener(stopListener)
128+
},
116129
async onError(resp) {
130+
if (resp instanceof Error) throw resp
131+
port.onMessage.removeListener(stopListener)
117132
if (resp.status === 403) {
118133
throw new Error('CLOUDFLARE')
119134
}

src/background/apis/openai-api.mjs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ export async function generateAnswersWithGptCompletionApi(
3535
modelName,
3636
) {
3737
const controller = new AbortController()
38+
const stopListener = (msg) => {
39+
if (msg.stop) {
40+
console.debug('stop generating')
41+
port.postMessage({ done: true })
42+
controller.abort()
43+
port.onMessage.removeListener(stopListener)
44+
}
45+
}
46+
port.onMessage.addListener(stopListener)
3847
port.onDisconnect.addListener(() => {
3948
console.debug('port disconnected')
4049
controller.abort()
@@ -79,8 +88,12 @@ export async function generateAnswersWithGptCompletionApi(
7988
port.postMessage({ answer: answer, done: false, session: null })
8089
},
8190
async onStart() {},
82-
async onEnd() {},
91+
async onEnd() {
92+
port.onMessage.removeListener(stopListener)
93+
},
8394
async onError(resp) {
95+
if (resp instanceof Error) throw resp
96+
port.onMessage.removeListener(stopListener)
8497
if (resp.status === 403) {
8598
throw new Error('CLOUDFLARE')
8699
}
@@ -99,6 +112,15 @@ export async function generateAnswersWithGptCompletionApi(
99112
*/
100113
export async function generateAnswersWithChatgptApi(port, question, session, apiKey, modelName) {
101114
const controller = new AbortController()
115+
const stopListener = (msg) => {
116+
if (msg.stop) {
117+
console.debug('stop generating')
118+
port.postMessage({ done: true })
119+
controller.abort()
120+
port.onMessage.removeListener(stopListener)
121+
}
122+
}
123+
port.onMessage.addListener(stopListener)
102124
port.onDisconnect.addListener(() => {
103125
console.debug('port disconnected')
104126
controller.abort()
@@ -142,8 +164,12 @@ export async function generateAnswersWithChatgptApi(port, question, session, api
142164
port.postMessage({ answer: answer, done: false, session: null })
143165
},
144166
async onStart() {},
145-
async onEnd() {},
167+
async onEnd() {
168+
port.onMessage.removeListener(stopListener)
169+
},
146170
async onError(resp) {
171+
if (resp instanceof Error) throw resp
172+
port.onMessage.removeListener(stopListener)
147173
if (resp.status === 403) {
148174
throw new Error('CLOUDFLARE')
149175
}

src/background/index.mjs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ Browser.runtime.onConnect.addListener((port) => {
5151
console.debug('connected')
5252
port.onMessage.addListener(async (msg) => {
5353
console.debug('received msg', msg)
54-
const config = await getUserConfig()
5554
const session = msg.session
55+
if (!session) return
56+
const config = await getUserConfig()
5657
if (session.useApiKey == null) {
5758
session.useApiKey = isUsingApiKey(config)
5859
}
@@ -84,8 +85,10 @@ Browser.runtime.onConnect.addListener((port) => {
8485
}
8586
} catch (err) {
8687
console.error(err)
87-
port.postMessage({ error: err.message })
88-
cache.delete(KEY_ACCESS_TOKEN)
88+
if (!err.message.includes('aborted')) {
89+
port.postMessage({ error: err.message })
90+
cache.delete(KEY_ACCESS_TOKEN)
91+
}
8992
}
9093
})
9194
})

src/components/ConversationCard/index.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ function ConversationCard(props) {
223223
type={data.type}
224224
session={data.session}
225225
done={data.done}
226+
port={port}
226227
/>
227228
))}
228229
</div>

src/components/ConversationItem/index.jsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import CopyButton from '../CopyButton'
55
import PropTypes from 'prop-types'
66
import MarkdownRender from '../MarkdownRender/markdown.jsx'
77

8-
export function ConversationItem({ type, content, session, done }) {
8+
export function ConversationItem({ type, content, session, done, port }) {
99
const [collapsed, setCollapsed] = useState(false)
1010

1111
switch (type) {
@@ -36,6 +36,17 @@ export function ConversationItem({ type, content, session, done }) {
3636
<div className="gpt-header">
3737
<p>{session ? 'ChatGPT:' : 'Loading...'}</p>
3838
<div style="display: flex; gap: 15px;">
39+
{!done && (
40+
<button
41+
type="button"
42+
className="normal-button"
43+
onClick={() => {
44+
port.postMessage({ stop: true })
45+
}}
46+
>
47+
Stop
48+
</button>
49+
)}
3950
{done && session && session.conversationId && (
4051
<FeedbackForChatGPTWeb
4152
messageId={session.messageId}
@@ -97,6 +108,7 @@ ConversationItem.propTypes = {
97108
content: PropTypes.string.isRequired,
98109
session: PropTypes.object.isRequired,
99110
done: PropTypes.bool.isRequired,
111+
port: PropTypes.object.isRequired,
100112
}
101113

102114
export default ConversationItem

src/content-script/styles.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,15 @@
167167
.gpt-util-icon {
168168
cursor: pointer;
169169
}
170+
171+
.normal-button {
172+
border: 1px solid;
173+
border-color: var(--theme-border-color);
174+
background-color: var(--theme-color);
175+
color: var(--font-color);
176+
border-radius: 5px;
177+
cursor: pointer;
178+
}
170179
}
171180

172181
.error {

src/utils/fetch-sse.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import { streamAsyncIterable } from './stream-async-iterable'
33

44
export async function fetchSSE(resource, options) {
55
const { onMessage, onStart, onEnd, onError, ...fetchOptions } = options
6-
const resp = await fetch(resource, fetchOptions)
6+
const resp = await fetch(resource, fetchOptions).catch(async (err) => {
7+
await onError(err)
8+
})
9+
if (!resp) return
710
if (!resp.ok) {
811
await onError(resp)
12+
return
913
}
1014
const parser = createParser((event) => {
1115
if (event.type === 'event') {

0 commit comments

Comments
 (0)