Skip to content
This repository was archived by the owner on Sep 28, 2023. It is now read-only.

Commit 8780f25

Browse files
committed
New features + bug fixes
- Improved Options page - Added Whisper API transcription logic for voice commands - Added custom question box - Multiple bug fixes with model selection and defaults.
1 parent 98a6b0e commit 8780f25

21 files changed

+1133
-350
lines changed

package-lock.json

Lines changed: 105 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"rehype-highlight": "^6.0.0",
2727
"swr": "^2.0.0",
2828
"uuid": "^9.0.0",
29-
"marked": "^4.2.12"
29+
"marked": "^4.2.12",
30+
"react-rnd": "10.4.1"
3031
},
3132
"devDependencies": {
3233
"@types/fs-extra": "^9.0.13",
@@ -36,6 +37,7 @@
3637
"@typescript-eslint/eslint-plugin": "^5.47.0",
3738
"@typescript-eslint/parser": "^5.47.0",
3839
"@types/marked": "^4.0.8",
40+
"@primer/octicons-react": "^17.9.0",
3941
"archiver": "^5.3.1",
4042
"autoprefixer": "^10.4.13",
4143
"chokidar-cli": "^3.0.0",

src/background/index.ts

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { getProviderConfigs, ProviderType } from '../config'
33
import { ChatGPTProvider, getChatGPTAccessToken, sendMessageFeedback } from './providers/chatgpt'
44
import { OpenAIProvider } from './providers/openai'
55
import { Provider } from './types'
6+
import { Buffer } from 'buffer'
67

78
async function generateAnswers(port: Browser.Runtime.Port, question: string) {
89
const providerConfigs = await getProviderConfigs()
@@ -29,40 +30,89 @@ async function generateAnswers(port: Browser.Runtime.Port, question: string) {
2930
prompt: question,
3031
signal: controller.signal,
3132
onEvent(event) {
33+
console.log("debug")
3234
if (event.type === 'done') {
3335
port.postMessage({ event: 'DONE' })
3436
return
3537
}
3638
port.postMessage(event.data)
3739
},
3840
})
41+
}
42+
43+
function dataURLtoBlob(dataUrl: string): Blob {
44+
const base64Regex = /^data:.+\/(.+);base64,(.*)$/;
45+
const match = dataUrl.match(base64Regex);
46+
if (!match) {
47+
throw new Error('Invalid data URL format');
48+
}
49+
50+
const mimeString = match[1];
51+
const base64Data = match[2];
52+
const byteString = Buffer.from(base64Data, 'base64').toString('binary');
53+
const ab = new ArrayBuffer(byteString.length);
54+
const ia = new Uint8Array(ab);
55+
for (let i = 0; i < byteString.length; i++) {
56+
ia[i] = byteString.charCodeAt(i);
57+
}
58+
return new Blob([ab], { type: mimeString });
3959
}
4060

41-
Browser.runtime.onConnect.addListener((port) => {
42-
port.onMessage.addListener(async (msg) => {
43-
console.debug('received msg', msg)
61+
async function transcribeAudio(port: Browser.Runtime.Port, dataUrl: string) {
62+
const providerConfigs = await getProviderConfigs();
63+
64+
const { apiKey } = providerConfigs.configs[ProviderType.API]!;
65+
if (!apiKey) {
66+
throw new Error('No API token available. Please add it in the config.');
67+
}
68+
69+
const provider = new OpenAIProvider(apiKey, 'whisper-1');
70+
const audioBlob = dataURLtoBlob(dataUrl);
71+
const audioFile = new File([audioBlob], 'recorded_audio.wav', { type: 'audio/wav' });
72+
4473
try {
45-
await generateAnswers(port, msg.question)
74+
const data = await provider.transcribeAudio(audioFile);
75+
port.postMessage({ event: 'DONE', data });
4676
} catch (err: any) {
47-
console.error(err)
48-
port.postMessage({ error: err.message })
77+
console.error(err);
78+
port.postMessage({ error: err.message });
4979
}
50-
})
51-
})
80+
}
5281

53-
Browser.runtime.onMessage.addListener(async (message) => {
54-
if (message.type === 'FEEDBACK') {
55-
const token = await getChatGPTAccessToken()
56-
await sendMessageFeedback(token, message.data)
57-
} else if (message.type === 'OPEN_OPTIONS_PAGE') {
58-
Browser.runtime.openOptionsPage()
59-
} else if (message.type === 'GET_ACCESS_TOKEN') {
60-
return getChatGPTAccessToken()
82+
Browser.runtime.onConnect.addListener((port) => {
83+
port.onMessage.addListener(async (msg) => {
84+
console.debug('received msg', msg);
85+
try {
86+
if (msg.type === 'GENERATE_ANSWERS') {
87+
await generateAnswers(port, msg.question);
88+
} else if (msg.type === 'TRANSCRIBE_AUDIO') {
89+
console.log("received", msg.dataUrl)
90+
await transcribeAudio(port, msg.dataUrl);
6191
}
62-
})
63-
64-
Browser.runtime.onInstalled.addListener((details) => {
65-
if (details.reason === 'install') {
66-
Browser.runtime.openOptionsPage()
92+
} catch (err: any) {
93+
console.error(err);
94+
port.postMessage({ error: err.message });
6795
}
68-
})
96+
});
97+
});
98+
99+
Browser.runtime.onMessage.addListener(async (message) => {
100+
if (message.type === 'FEEDBACK') {
101+
const token = await getChatGPTAccessToken()
102+
await sendMessageFeedback(token, message.data)
103+
} else if (message.type === 'OPEN_OPTIONS_PAGE') {
104+
Browser.runtime.openOptionsPage()
105+
} else if (message.type === 'GET_ACCESS_TOKEN') {
106+
return getChatGPTAccessToken()
107+
} else if (message.type === 'CHECK_API_KEY') {
108+
const providerConfigs = await getProviderConfigs();
109+
const { apiKey } = providerConfigs.configs[ProviderType.API]!;
110+
return !!apiKey;
111+
}
112+
})
113+
114+
Browser.runtime.onInstalled.addListener((details) => {
115+
if (details.reason === 'install') {
116+
Browser.runtime.openOptionsPage()
117+
}
118+
})

src/background/providers/chatgpt.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ export class ChatGPTProvider implements Provider {
9292
}
9393
}
9494

95-
96-
9795
//const modelName = await this.getModelName()
9896
console.log('Using model:', this.model)
9997

src/background/providers/openai.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,32 @@ export class OpenAIProvider implements Provider {
9191
})
9292
return {}
9393
}
94+
95+
async transcribeAudio(file: File, prompt?: string): Promise<any> {
96+
const endpoint = 'https://api.openai.com/v1/audio/transcriptions';
97+
98+
const formData = new FormData();
99+
formData.append("file", file);
100+
formData.append("model", "whisper-1");
101+
formData.append("response_format", "json");
102+
formData.append("temperature", "0");
103+
104+
const response = await fetch(endpoint, {
105+
method: 'POST',
106+
headers: {
107+
Authorization: `Bearer ${this.token}`,
108+
},
109+
body: formData,
110+
});
111+
112+
if (!response.ok) {
113+
const errorData = await response.json();
114+
throw new Error(`Error: ${response.status} ${response.statusText} - ${JSON.stringify(errorData)}`);
115+
}
116+
117+
const data = await response.json();
118+
119+
console.log(data)
120+
return data;
121+
}
94122
}

0 commit comments

Comments
 (0)