Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
Kypaku committed May 8, 2023
1 parent b1173cf commit 2136f45
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 152 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module.exports = {
"no-throw-literal": "warn",
"prefer-regex-literals": "warn",
"no-multiple-empty-lines": "warn",
'no-unused-expressions': 'warn',
"no-useless-escape": "warn",
"vue/multi-word-component-names": "warn",
"no-return-assign": "warn",
Expand Down
155 changes: 100 additions & 55 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,51 +1,42 @@
<template>
<div class="app">
<div class="text-5xl w-full text-center mt-10">
<div class="app pt-10">
<div class="text-5xl w-full text-center">
<b>Vue.js OpenAI API Example</b>
</div>
<div class="description container mx-auto mt-8 pr-2">
An example project based on Vue CLI to demonstrate basic OpenAI GPT possibilities. Create your own Chat GPT!
<div>
<a target="_blank" :href="currentGuide">OpenAI API Guide</a>
</div>
</div>

<div class="main container mx-auto mt-6 pl-1 pb-3">
<div class="settingsWrapper">
<button @click="showApiKeyInput" class="bg-white">
<span v-if="!apiKeyVisible">Set API KEY</span>
<span v-else style="color: red"
>Hide api-key input &#215;</span
>
</button>
<div v-if="apiKeyVisible" class="mt-4">
To get an API KEY you need to register new OPEN API account
and then visit
<div class="description container mx-auto mt-8 pr-2 text-xl">
An example project based on Vue CLI to demonstrate basic OpenAI GPT possibilities.<br/> Create your own Chat GPT!
<div>
<a target="_blank" :href="currentGuide">OpenAI API Guide</a>
</div>
</div>
<Accordeon title="Set API KEY" v-model:value="apiKeyVisible" class="mt-8 api-key" >
<div>
<span class="text-sm" >
To get an API KEY you need to register new OPEN API account
and then visit
</span>
<a
href="https://platform.openai.com/account/api-keys"
target="_blank"
>
https://platform.openai.com/account/api-keys
</a>
</div>
<InputText
v-if="apiKeyVisible"
<InputAPIKey
v-model:value="apiKey"
:label="'API Key:'"
class="w-3/4 mt-4"
:useLocalStorage="true"
@update:value="
(val) => {
api.setApiKey(val), (apiKeyNeeded = false);
}
"
placeholder="Paste a key here"
/>

<button @click="showSettings" class="bg-white">
<span v-if="!settings" class="underline">Settings</span>
<span v-else style="color: red">Close settings &#215;</span>
</button>

</Accordeon>
<Accordeon title="Settings" v-model:value="settings" class="mt-3 api-key" >
<OpenAITextSettings
v-if="settings && tab === ''"
v-model:value="textOpts"
Expand All @@ -54,16 +45,17 @@
<button v-if="settings" @click="saveSettings">
Save settings
</button>
</div>
</Accordeon>

<Tabs
v-model:value="tab"
:tabs="tabs"
@click="clearResult()"
class="mt-8 w-full"
class="mt-10 w-full"
/>

<InputFile
class="mt-4"
v-if="tab === 'audio'"
@update:value="(val) => runTranscribe(val)"
></InputFile>
Expand All @@ -77,50 +69,62 @@
v-model:value="prompt"
@setPromt="(val) => $emit('update:value', val)"
:label="'Prompt:'"
class="w-4/5 rounded-lg mt-8 p-1"
class="w-full rounded-lg mt-8"
:rows="10"
/>
<button
v-if="tab !== 'audio'"
:disabled="isLoading || !prompt"
@click="run"
class="mt-2 bg-gray-300 px-2 py-1"
class="mt-2 bg-gray-300 run-btn px-8 py-2 text-white rounded"
>
{{ isLoading ? "Loading..." : "Run" }}
<b>{{ isLoading ? "Loading..." : "Run" }}</b>

</button>
<div class="image-wrapper" v-if="tab === 'image'">
<div class="image-wrapper" v-if="tab === 'image' && result" ref="result">
<span>Result:</span>
<img :src="result" alt="result" v-if="result" />
<img :src="result" alt="result" />
</div>
<InputTextarea
v-else
v-else-if="result"
v-model:value="result"
:label="'Result:'"
disabled
class="mt-8 w-1/2"
class="mt-8"
:rows="10"
ref="result"
/>
<Error :value="error" v-if="error" class="mt-2" />

</div>
</div>
</template>

<script lang="ts">
import SimpleGPT from "./api/openai";
import { defineComponent } from "@vue/runtime-core";
import InputText from "./components/misc/InputText.vue";
import Error from "./components/misc/Error.vue";
import InputTextarea from "./components/misc/InputTextarea.vue";
import Tabs, { ITab } from "./components/misc/Tabs.vue";
import OpenAITextSettings from "./components/openai/OpenAITextSettings.vue";
import InputFile from "./components/misc/InputFile.vue";
import Accordeon from "./components/misc/Accordeon.vue";
import InputAPIKey from "./components/openai/InputAPIKey.vue";
import ls from "local-storage";
export default defineComponent({
components: {
Tabs,
InputTextarea,
InputText,
OpenAITextSettings,
InputFile,
Accordeon,
InputAPIKey,
Error,
},
data() {
return {
error: "",
guides: {
code: "https://platform.openai.com/docs/guides/code",
text: "https://platform.openai.com/docs/guides/completion",
Expand Down Expand Up @@ -149,7 +153,7 @@
waitResponse: true,
prompt: "",
text: "",
apiKey: process.env.OPENAI_API_KEY || "",
apiKey: process.env.OPENAI_API_KEY || ls("openAIKey") || "",
api: new SimpleGPT({ key: process.env.OPENAI_API_KEY || "" }),
apiKeyNeeded: false,
apiKeyVisible: false,
Expand Down Expand Up @@ -187,11 +191,12 @@
this.prompt = "";
},
async runTranscribe(val: any) {
if (this.apiKeyNeeded) {
alert("Enter your API KEY");
if (!this.apiKey) {
alert("You need to set your API KEY before running");
return null;
}
if (!this.isTranscribing) {
this.error = ''
this.isTranscribing = true;
try {
const blob = new Blob([val.target.files[0]], {
Expand All @@ -200,29 +205,35 @@
const formData = new FormData();
formData.append("file", blob, "test.webm");
formData.append("model", "whisper-1");
const token = localStorage.getItem("key");
const requestOptions = {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
Authorization: `Bearer ${this.apiKey}`,
},
body: formData,
};
const text = await this.api.transcribe(requestOptions);
this.result = text || "";
} catch (e) {
console.error("App error: " + e);
setTimeout(() => {
(this.$refs?.result as any)?.scrollIntoView?.();
}, 0);
} catch (e: any) {
console.error("App error: " + e, e.response);
if (e?.response?.data?.error?.message) {
this.error = e?.response.data.error.message;
}
} finally {
this.isTranscribing = false;
}
}
},
async run() {
if (this.apiKeyNeeded) {
alert("Enter your API KEY");
if (!this.apiKey) {
alert("You need to set your API KEY before running");
return null;
}
if (!this.isLoading) {
this.error = ''
this.isLoading = true;
const handlers = {
code: "getCodeFirst",
Expand All @@ -240,14 +251,28 @@
](this.prompt, this.textOpts);
}
this.result = res || "";
} catch (e) {
setTimeout(() => {
(this.$refs?.result as any)?.scrollIntoView?.();
(this.$refs?.result as any)?.$el?.scrollIntoView?.();
}, 0);
} catch (e: any) {
console.error("App error: " + e);
if (e?.response?.data?.error?.message) {
this.error = e?.response.data.error.message;
}
} finally {
this.isLoading = false;
}
}
},
},
created() {
if (!this.apiKey) {
this.apiKeyVisible = true;
} else {
this.api.setApiKey(this.apiKey);
}
},
mounted() {
const savedSettings = localStorage.getItem("settings");
if (savedSettings === null) return;
Expand All @@ -259,19 +284,39 @@
});
</script>

<style lang="scss" scoped>a {
<style lang="scss" scoped>
.run-btn{
background: #7759de;
&:disabled {
opacity: 0.6;
pointer-events: none;
}
}
::v-deep .api-key{
width: 500px;
max-width: 100%;
.tab__link {
background: #e0f7ea;
display: flex;
align-items: center;
border-radius: 4px;
}
}
.main{
width: 900px;
}
a {
@apply underline text-blue-600 hover:text-blue-800;
}
.app {
background: linear-gradient(
to right,
rgb(202, 245, 194),
rgb(223, 207, 239)
);
background: linear-gradient(to bottom, rgb(255 255 255), rgb(206 255 228));
min-height: 100vh;
}
.description {
text-align: right;
text-align: left;
}
.settingsWrapper {
display: flex;
Expand Down
Loading

0 comments on commit 2136f45

Please sign in to comment.