Skip to content

Commit

Permalink
feat: connecting api requests
Browse files Browse the repository at this point in the history
  • Loading branch information
ayangweb committed Mar 14, 2023
1 parent f2153c7 commit b28a255
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 54 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
VITE_APP_NAME=ChatGPT
VITE_OPEN_AI_URL=https://api.openai.com/v1/chat/completions
VITE_OPEN_AI_API_KEY=
7 changes: 7 additions & 0 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
},
"globalShortcut": {
"all": true
},
"http": {
"request": true,
"scope": [
"https://**",
"http://**"
]
}
},
"bundle": {
Expand Down
35 changes: 23 additions & 12 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script setup lang="ts">
import { appWindow } from '@tauri-apps/api/window'
import { register } from '@tauri-apps/api/globalShortcut'
import { initSQL } from '@/sqls'
import {
useThemeStore,
useUuidStore,
Expand All @@ -11,11 +10,10 @@ import {
} from '@/stores'
// TODO: 首次加载有问题,获取不到初始化的角色列表
initSQL()
const { themeClass } = storeToRefs(useThemeStore())
const { uuid } = storeToRefs(useUuidStore())
const { currentRecord, recordList } = storeToRefs(useRecordStore())
const { currentRecord } = storeToRefs(useRecordStore())
const { currentRole } = storeToRefs(useRoleStore())
const { isFix } = storeToRefs(useFixedStore())
Expand All @@ -24,7 +22,7 @@ const windowFocused = ref(true)
onMounted(async () => {
// 监听窗口有无获取焦点
appWindow.onFocusChanged(({ payload }) => {
if (!isFix.value) appWindow.hide()
if (!payload && !isFix.value) appWindow.hide()
windowFocused.value = payload
})
Expand All @@ -48,13 +46,20 @@ onMounted(async () => {
</div>

<div class="flex-1 cursor-default overflow-auto">
<!-- <div v-for="(item, index) of recordList.slice(1)" :key="index">
<Avatar :value="!(index % 2) ? uuid : undefined" />
</div> -->
<!-- TODO: 角色如何与历史对话绑定 -->
<template v-if="currentRecord">
<div class="py-2" v-for="item in 100" :key="item">
{{ item }}
<div
class="flex items-start p-2"
v-for="(item, index) of currentRecord.data?.slice(1)"
:key="index"
>
<Avatar
class="w-14!"
:value="!(index % 2) ? uuid : currentRole?.name"
/>
<div>
{{ item.content }}
</div>
</div>
</template>
Expand All @@ -64,9 +69,15 @@ onMounted(async () => {
v-else
>
<!-- TODO: 丰富此处信息 -->
<span>⌥ + x 唤醒窗口</span>
<span>↩ 发送消息</span>
<span>⇧ + ↩︎ 或者 ⌃ + ↩︎ 或者 ⌥ + ↩︎ 换行</span>
<span>
<a-typography-text code>Alt</a-typography-text> +
<a-typography-text code>X</a-typography-text> 唤醒窗口
</span>
<span
><a-typography-text code>Shift</a-typography-text> +
<a-typography-text code>Enter</a-typography-text> 发送消息
</span>
<span><a-typography-text code>Enter</a-typography-text> 换行</span>
</div>
</div>
Expand Down
58 changes: 58 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { fetch, Body } from '@tauri-apps/api/http'
import { dialogErrorMessage } from '@/utils'
import type { FetchOptions } from '@tauri-apps/api/http'
import type { RecordData } from '@/types'
import { useApiKeyStore, useRecordStore } from '@/stores'

/**
* 请求总入口
* @param url 请求地址
* @param options 请求参数
*/
export const request = async (url: string, options?: FetchOptions) => {
try {
const { method, headers } = options || {}

const { data }: Record<string, any> = await fetch(url, {
...options,
method: method || 'GET',
timeout: 1000 * 60,
headers: {
...headers,
'user-agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}
})

const { error, usage, choices } = data

if (error) throw new Error(error.message)

return {
usage,
message: choices[0].message
}
} catch ({ message }: any) {
dialogErrorMessage('请求出错:' + message)
}
}

/**
* 获取 openai 对话消息
* @param messages 消息列表
*/
export const getOpenAIResultApi = async () => {
const { apiKey } = useApiKeyStore()
const { currentRecord } = useRecordStore()

return await request(import.meta.env.VITE_OPEN_AI_URL, {
method: 'POST',
body: Body.json({
model: 'gpt-3.5-turbo',
messages: currentRecord?.data
}),
headers: {
Authorization: `Bearer ${apiKey}`
}
})
}
32 changes: 0 additions & 32 deletions src/api/request.ts

This file was deleted.

5 changes: 3 additions & 2 deletions src/components/Input/components/RoleList.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { IconEdit, IconCheck, IconClose } from '@arco-design/web-vue/es/icon'
import { IconEdit, IconCheck, IconDelete } from '@arco-design/web-vue/es/icon'
import { useRoleStore } from '@/stores'
import { DEFAULT_ROLE } from '@/constants'
import type { TablePayload } from '@/types'
Expand Down Expand Up @@ -102,7 +102,8 @@ watch(currentRole, handleUpdate)
<IconEdit @click="handleEdit(item)" v-else />
<IconClose @click="deleteRole(item.id!)" />
<!-- TODO:编辑的时候变成 x -->
<IconDelete @click="deleteRole(item.id!)" />
</div>
</li>
</ul>
Expand Down
27 changes: 22 additions & 5 deletions src/components/Input/index.vue
Original file line number Diff line number Diff line change
@@ -1,34 +1,51 @@
<script lang="ts" setup>
import { useRecordStore } from '@/stores'
import { appWindow } from '@tauri-apps/api/window'
const recordStore = useRecordStore()
const { getAiMessage } = recordStore
const { isThinking } = storeToRefs(recordStore)
const textAreaElement = ref<HTMLTextAreaElement | null>(null)
const textAreaValue = ref('')
const onKeydown = (event: KeyboardEvent) => {
const keyName = event.key.toLowerCase()
if (keyName === 'enter') {
if (!event.shiftKey && !event.ctrlKey && !event.altKey) {
if (event.shiftKey) {
event.preventDefault()
const value = textAreaValue.value.trim()
if (!value) return
// TODO: 请求接口
getAiMessage(value)
event.target?.blur()
textAreaElement.value?.blur()
textAreaValue.value = ''
}
}
}
onMounted(() => {
appWindow.onFocusChanged(() => {
textAreaElement.value?.focus()
})
})
</script>

<template>
<div class="app-input flex items-center gap-2">
<RoleList />

<a-textarea
ref="textAreaElement"
class="bordered bg-transparent!"
placeholder="有什么问题尽管问我"
allow-clear
:placeholder="isThinking ? 'AI 正在思考...' : '有什么问题尽管问我'"
v-model="textAreaValue"
:disabled="isThinking"
@keydown="onKeydown"
></a-textarea>
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/components/ReAnswer/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IconRefresh } from '@arco-design/web-vue/es/icon'
import { useRecordStore } from '@/stores'
const recordStore = useRecordStore()
const { updateRecord } = recordStore
const { getAiMessage } = recordStore
const { currentRecord } = storeToRefs(recordStore)
const handleClick = () => {
Expand All @@ -12,9 +12,11 @@ const handleClick = () => {
const newRecord = { ...currentRecord.value }
newRecord.data?.pop()
console.log('newRecord', newRecord)
currentRecord.value = newRecord
updateRecord(newRecord)
getAiMessage()
}
</script>

Expand Down
13 changes: 13 additions & 0 deletions src/stores/apiKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const useApiKeyStore = defineStore(
'apiKeyStore',
() => {
const apiKey = ref('')

return {
apiKey
}
},
{
persist: true
}
)
1 change: 1 addition & 0 deletions src/stores/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './uuid'
export * from './record'
export * from './role'
export * from './fixed'
export * from './apiKey'
44 changes: 43 additions & 1 deletion src/stores/record.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,55 @@
import { selectSQL, insertSQL, updateSQL, deleteSQL } from '@/sqls'
import type { TablePayload } from '@/types'
import { getOpenAIResultApi } from '@/api'
import { useRoleStore } from '.'
import type { TablePayload, RecordData } from '@/types'

export const useRecordStore = defineStore('recordStore', () => {
const currentRecord = ref<TablePayload>()

const isThinking = ref(false)

const recordList = ref<TablePayload[]>([])

const createNewRecord = () => {
currentRecord.value = undefined
}

const getAiMessage = async (value?: string) => {
isThinking.value = true

if (!currentRecord.value) {
const newRecord: TablePayload = {
title: value,
data: []
}

const { currentRole } = useRoleStore()

newRecord.data?.push(
{
role: 'system',
content: currentRole?.description || ''
},
{
role: 'user',
content: value
}
)

currentRecord.value = newRecord
} else if (!value) {
value = currentRecord.value.data?.at(-1)?.content
}

const result = await getOpenAIResultApi()

isThinking.value = false

if (!result) return

currentRecord.value.data?.push(result?.message)
}

const getRecord = async () => {
recordList.value = await selectSQL('history')

Expand Down Expand Up @@ -48,8 +88,10 @@ export const useRecordStore = defineStore('recordStore', () => {

return {
currentRecord,
isThinking,
recordList,
createNewRecord,
getAiMessage,
addRecord,
updateRecord,
deleteRecord
Expand Down
3 changes: 3 additions & 0 deletions src/stores/role.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { selectSQL, insertSQL, updateSQL, deleteSQL } from '@/sqls'
import { initSQL } from '@/sqls'
import type { TablePayload } from '@/types'

export const useRoleStore = defineStore(
Expand All @@ -9,6 +10,8 @@ export const useRoleStore = defineStore(
const roleList = ref<TablePayload[]>()

const getRoleList = async () => {
await initSQL()

roleList.value = await selectSQL('role')

if (currentRole.value) {
Expand Down
1 change: 1 addition & 0 deletions src/vite-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
interface ImportMetaEnv {
readonly VITE_APP_NAME: string
readonly VITE_OPEN_AI_URL: string
readonly VITE_OPEN_AI_API_KEY: string
}

// eslint-disable-next-line no-unused-vars
Expand Down

0 comments on commit b28a255

Please sign in to comment.