@@ -5,24 +5,25 @@ import InputBox from '../InputBox'
55import ConversationItem from '../ConversationItem'
66import { createElementAtPosition , isFirefox , isMobile , isSafari } from '../../utils'
77import {
8- LinkExternalIcon ,
98 ArchiveIcon ,
109 DesktopDownloadIcon ,
10+ LinkExternalIcon ,
1111 MoveToBottomIcon ,
1212} from '@primer/octicons-react'
13- import { WindowDesktop , XLg , Pin } from 'react-bootstrap-icons'
13+ import { Pin , WindowDesktop , XLg } from 'react-bootstrap-icons'
1414import FileSaver from 'file-saver'
1515import { render } from 'preact'
1616import FloatingToolbar from '../FloatingToolbar'
1717import { useClampWindowSize } from '../../hooks/use-clamp-window-size'
18- import { ModelMode , Models } from '../../config/index.mjs'
18+ import { bingWebModelKeys , getUserConfig , ModelMode , Models } from '../../config/index.mjs'
1919import { useTranslation } from 'react-i18next'
2020import DeleteButton from '../DeleteButton'
2121import { useConfig } from '../../hooks/use-config.mjs'
2222import { createSession } from '../../services/local-session.mjs'
2323import { v4 as uuidv4 } from 'uuid'
2424import { initSession } from '../../services/init-session.mjs'
2525import { findLastIndex } from 'lodash-es'
26+ import { generateAnswersWithBingWebApi } from '../../services/apis/bing-web.mjs'
2627
2728const logo = Browser . runtime . getURL ( 'logo.png' )
2829
@@ -48,6 +49,7 @@ function ConversationCard(props) {
4849 const windowSize = useClampWindowSize ( [ 750 , 1500 ] , [ 250 , 1100 ] )
4950 const bodyRef = useRef ( null )
5051 const [ completeDraggable , setCompleteDraggable ] = useState ( false )
52+ const useForegroundFetch = bingWebModelKeys . includes ( session . modelName )
5153
5254 /**
5355 * @type {[ConversationItemData[], (conversationItemData: ConversationItemData[]) => void] }
@@ -96,12 +98,12 @@ function ConversationCard(props) {
9698 }
9799 } , [ conversationItemData ] )
98100
99- useEffect ( ( ) => {
101+ useEffect ( async ( ) => {
100102 // when the page is responsive, session may accumulate redundant data and needs to be cleared after remounting and before making a new request
101103 if ( props . question ) {
102104 const newSession = initSession ( { question : props . question } )
103105 setSession ( newSession )
104- port . postMessage ( { session : newSession } )
106+ await postMessage ( { session : newSession } )
105107 }
106108 } , [ props . question ] ) // usually only triggered once
107109
@@ -125,6 +127,100 @@ function ConversationCard(props) {
125127 } )
126128 }
127129
130+ const portMessageListener = ( msg ) => {
131+ if ( msg . answer ) {
132+ updateAnswer ( msg . answer , false , 'answer' )
133+ }
134+ if ( msg . session ) {
135+ if ( msg . done ) msg . session = { ...msg . session , isRetry : false }
136+ setSession ( msg . session )
137+ }
138+ if ( msg . done ) {
139+ updateAnswer ( '' , true , 'answer' , true )
140+ setIsReady ( true )
141+ }
142+ if ( msg . error ) {
143+ switch ( msg . error ) {
144+ case 'UNAUTHORIZED' :
145+ updateAnswer (
146+ `${ t ( 'UNAUTHORIZED' ) } <br>${ t ( 'Please login at https://chat.openai.com first' ) } ${
147+ isSafari ( ) ? `<br>${ t ( 'Then open https://chat.openai.com/api/auth/session' ) } ` : ''
148+ } <br>${ t ( 'And refresh this page or type you question again' ) } ` +
149+ `<br><br>${ t (
150+ 'Consider creating an api key at https://platform.openai.com/account/api-keys' ,
151+ ) } `,
152+ false ,
153+ 'error' ,
154+ )
155+ break
156+ case 'CLOUDFLARE' :
157+ updateAnswer (
158+ `${ t ( 'OpenAI Security Check Required' ) } <br>${
159+ isSafari ( )
160+ ? t ( 'Please open https://chat.openai.com/api/auth/session' )
161+ : t ( 'Please open https://chat.openai.com' )
162+ } <br>${ t ( 'And refresh this page or type you question again' ) } ` +
163+ `<br><br>${ t (
164+ 'Consider creating an api key at https://platform.openai.com/account/api-keys' ,
165+ ) } `,
166+ false ,
167+ 'error' ,
168+ )
169+ break
170+ default :
171+ if ( conversationItemData [ conversationItemData . length - 1 ] . content . includes ( 'gpt-loading' ) )
172+ updateAnswer ( msg . error , false , 'error' )
173+ else
174+ setConversationItemData ( [
175+ ...conversationItemData ,
176+ new ConversationItemData ( 'error' , msg . error ) ,
177+ ] )
178+ break
179+ }
180+ setIsReady ( true )
181+ }
182+ }
183+
184+ const foregroundMessageListeners = useRef ( [ ] )
185+
186+ /**
187+ * @param {Session|undefined } session
188+ * @param {boolean|undefined } stop
189+ */
190+ const postMessage = async ( { session, stop } ) => {
191+ if ( useForegroundFetch ) {
192+ foregroundMessageListeners . current . forEach ( ( listener ) => listener ( { session, stop } ) )
193+ if ( session ) {
194+ const fakePort = {
195+ postMessage : ( msg ) => {
196+ portMessageListener ( msg )
197+ } ,
198+ onMessage : {
199+ addListener : ( listener ) => {
200+ foregroundMessageListeners . current . push ( listener )
201+ } ,
202+ removeListener : ( listener ) => {
203+ foregroundMessageListeners . current . splice (
204+ foregroundMessageListeners . current . indexOf ( listener ) ,
205+ 1 ,
206+ )
207+ } ,
208+ } ,
209+ onDisconnect : {
210+ addListener : ( ) => { } ,
211+ removeListener : ( ) => { } ,
212+ } ,
213+ }
214+ const bingToken = ( await getUserConfig ( ) ) . bingAccessToken
215+ if ( session . modelName . includes ( 'bingFreeSydney' ) )
216+ await generateAnswersWithBingWebApi ( fakePort , session . question , session , bingToken , true )
217+ else await generateAnswersWithBingWebApi ( fakePort , session . question , session , bingToken )
218+ }
219+ } else {
220+ port . postMessage ( { session, stop } )
221+ }
222+ }
223+
128224 useEffect ( ( ) => {
129225 const portListener = ( ) => {
130226 setPort ( Browser . runtime . connect ( ) )
@@ -146,68 +242,17 @@ function ConversationCard(props) {
146242 }
147243 } , [ port ] )
148244 useEffect ( ( ) => {
149- const listener = ( msg ) => {
150- if ( msg . answer ) {
151- updateAnswer ( msg . answer , false , 'answer' )
152- }
153- if ( msg . session ) {
154- if ( msg . done ) msg . session = { ...msg . session , isRetry : false }
155- setSession ( msg . session )
245+ if ( useForegroundFetch ) {
246+ return ( ) => { }
247+ } else {
248+ port . onMessage . addListener ( portMessageListener )
249+ return ( ) => {
250+ port . onMessage . removeListener ( portMessageListener )
156251 }
157- if ( msg . done ) {
158- updateAnswer ( '' , true , 'answer' , true )
159- setIsReady ( true )
160- }
161- if ( msg . error ) {
162- switch ( msg . error ) {
163- case 'UNAUTHORIZED' :
164- updateAnswer (
165- `${ t ( 'UNAUTHORIZED' ) } <br>${ t ( 'Please login at https://chat.openai.com first' ) } ${
166- isSafari ( ) ? `<br>${ t ( 'Then open https://chat.openai.com/api/auth/session' ) } ` : ''
167- } <br>${ t ( 'And refresh this page or type you question again' ) } ` +
168- `<br><br>${ t (
169- 'Consider creating an api key at https://platform.openai.com/account/api-keys' ,
170- ) } `,
171- false ,
172- 'error' ,
173- )
174- break
175- case 'CLOUDFLARE' :
176- updateAnswer (
177- `${ t ( 'OpenAI Security Check Required' ) } <br>${
178- isSafari ( )
179- ? t ( 'Please open https://chat.openai.com/api/auth/session' )
180- : t ( 'Please open https://chat.openai.com' )
181- } <br>${ t ( 'And refresh this page or type you question again' ) } ` +
182- `<br><br>${ t (
183- 'Consider creating an api key at https://platform.openai.com/account/api-keys' ,
184- ) } `,
185- false ,
186- 'error' ,
187- )
188- break
189- default :
190- if (
191- conversationItemData [ conversationItemData . length - 1 ] . content . includes ( 'gpt-loading' )
192- )
193- updateAnswer ( msg . error , false , 'error' )
194- else
195- setConversationItemData ( [
196- ...conversationItemData ,
197- new ConversationItemData ( 'error' , msg . error ) ,
198- ] )
199- break
200- }
201- setIsReady ( true )
202- }
203- }
204- port . onMessage . addListener ( listener )
205- return ( ) => {
206- port . onMessage . removeListener ( listener )
207252 }
208253 } , [ conversationItemData ] )
209254
210- const getRetryFn = ( session ) => ( ) => {
255+ const getRetryFn = ( session ) => async ( ) => {
211256 updateAnswer ( `<p class="gpt-loading">${ t ( 'Waiting for response...' ) } </p>` , false , 'answer' )
212257 setIsReady ( false )
213258
@@ -223,8 +268,8 @@ function ConversationCard(props) {
223268 const newSession = { ...session , isRetry : true }
224269 setSession ( newSession )
225270 try {
226- port . postMessage ( { stop : true } )
227- port . postMessage ( { session : newSession } )
271+ await postMessage ( { stop : true } )
272+ await postMessage ( { session : newSession } )
228273 } catch ( e ) {
229274 updateAnswer ( e , false , 'error' )
230275 }
@@ -348,8 +393,8 @@ function ConversationCard(props) {
348393 < DeleteButton
349394 size = { 16 }
350395 text = { t ( 'Clear Conversation' ) }
351- onConfirm = { ( ) => {
352- port . postMessage ( { stop : true } )
396+ onConfirm = { async ( ) => {
397+ await postMessage ( { stop : true } )
353398 Browser . runtime . sendMessage ( {
354399 type : 'DELETE_CONVERSATION' ,
355400 data : {
@@ -449,7 +494,7 @@ function ConversationCard(props) {
449494 enabled = { isReady }
450495 port = { port }
451496 reverseResizeDir = { props . pageMode }
452- onSubmit = { ( question ) => {
497+ onSubmit = { async ( question ) => {
453498 const newQuestion = new ConversationItemData ( 'question' , question )
454499 const newAnswer = new ConversationItemData (
455500 'answer' ,
@@ -461,7 +506,7 @@ function ConversationCard(props) {
461506 const newSession = { ...session , question, isRetry : false }
462507 setSession ( newSession )
463508 try {
464- port . postMessage ( { session : newSession } )
509+ await postMessage ( { session : newSession } )
465510 } catch ( e ) {
466511 updateAnswer ( e , false , 'error' )
467512 }
0 commit comments