Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support token unit switch #165

Merged
merged 1 commit into from
Apr 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div align=center>
<a href='https://github.com/bilibili-ayang/ChatGPT-Desktop'>
<a href='https://github.com/Synaptrix/ChatGPT-Desktop'>
<img height=100 src='./src-tauri/assets/icon.png' alt='icon' />
</a>

Expand All @@ -10,21 +10,21 @@
<h4>注意:软件本身不提供 API KEY,需要自行准备</h4>

<div>
<a href="https://github.com/bilibili-ayang/ChatGPT-Desktop/releases/latest">
<a href="https://github.com/Synaptrix/ChatGPT-Desktop/releases/latest">
<img alt="macOS" src="https://img.shields.io/badge/-macOS-black?style=flat-square&logo=apple&logoColor=white" />
</a>
<a href="https://github.com/bilibili-ayang/ChatGPT-Desktop/releases/latest">
<a href="https://github.com/Synaptrix/ChatGPT-Desktop/releases/latest">
<img alt="Windows" src="https://img.shields.io/badge/-Windows-blue?style=flat-square&logo=windows&logoColor=white" />
</a>
<a href="https://github.com/bilibili-ayang/ChatGPT-Desktop/releases/latest">
<a href="https://github.com/Synaptrix/ChatGPT-Desktop/releases/latest">
<img alt="Linux" src="https://img.shields.io/badge/-Linux-yellow?style=flat-square&logo=linux&logoColor=white" />
</a>
</div>

<div>
<img src="https://img.shields.io/github/license/bilibili-ayang/ChatGPT-Desktop?style=flat-square" />
<img src="https://img.shields.io/github/package-json/v/bilibili-ayang/ChatGPT-Desktop?style=flat-square" />
<img src="https://img.shields.io/github/downloads/bilibili-ayang/ChatGPT-Desktop/total?style=flat-square" />
<img src="https://img.shields.io/github/license/Synaptrix/ChatGPT-Desktop?style=flat-square" />
<img src="https://img.shields.io/github/package-json/v/Synaptrix/ChatGPT-Desktop?style=flat-square" />
<img src="https://img.shields.io/github/downloads/Synaptrix/ChatGPT-Desktop/total?style=flat-square" />
</div>
</div>

Expand Down Expand Up @@ -133,12 +133,12 @@ npm run build:icon

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=ChatGPT-Desktop/ChatGPT-Desktop&type=Date)](https://star-history.com/#ChatGPT-Desktop/ChatGPT-Desktop&Date)
[![Star History Chart](https://api.star-history.com/svg?repos=Synaptrix/ChatGPT-Desktop&type=Date)](https://star-history.com/#Synaptrix/ChatGPT-Desktop&Date)

## Contributors

<a href="https://github.com/bilibili-ayang/ChatGPT-Desktop/graphs/contributors">
<img src="https://contrib.rocks/image?repo=bilibili-ayang/ChatGPT-Desktop" />
<a href="https://github.com/Synaptrix/ChatGPT-Desktop/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Synaptrix/ChatGPT-Desktop" />
</a>

## License
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "1.0.0"
description = "ChatGPT-Desktop"
authors = ["orangelckc", "bilibili-ayang"]
license = "MIT"
repository = "https://github.com/bilibili-ayang/ChatGPT-Desktop"
repository = "https://github.com/Synaptrix/ChatGPT-Desktop"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
4 changes: 2 additions & 2 deletions src/api/request.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fetch, type FetchOptions } from '@tauri-apps/api/http'
import type { REQUEST_HOST } from '@/types'
import type { RequestHost } from '@/types'

/**
* 普通请求
Expand All @@ -8,7 +8,7 @@ import type { REQUEST_HOST } from '@/types'
*/
export const request = async (
url: string,
options?: FetchOptions & { host?: REQUEST_HOST }
options?: FetchOptions & { host?: RequestHost }
) => {
try {
const { method = 'GET', headers, host = 'OPENAI' } = options || {}
Expand Down
4 changes: 4 additions & 0 deletions src/assets/css/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
background-color: var(--scroll-thumb-color-hover);
}
}

&::selection {
background-color: #b4d0f6;
}
}

@font-face {
Expand Down
36 changes: 17 additions & 19 deletions src/components/Function/components/TokenUsage.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
<script setup lang="ts">
const { currentRole, textAreaValue } = storeToRefs(useRoleStore())
const { isMemory } = storeToRefs(useSettingsStore())
const { isMemory, tokenUnit } = storeToRefs(useSettingsStore())
const { currentSession, imageParams } = storeToRefs(useSessionStore())

const tokenUsage = ref(0)

const tokenExceed = computed(
() => !!textAreaValue.value && tokenUsage.value > 3800
() =>
currentSession.value?.type === 'text' &&
!!textAreaValue.value &&
tokenUsage.value > 3800
)

const ImagePrices = {
'256x256': 0.016,
'512x512': 0.018,
'1024x1024': 0.02
}

watch([textAreaValue, isMemory], async () => {
watchEffect(async () => {
if (currentSession.value?.type === 'image') {
const size = imageParams.value.size as keyof typeof ImagePrices
tokenUsage.value = ImagePrices[size] * imageParams.value.number
const size = imageParams.value.size as keyof typeof ImageCost
const cost = ImageCost[size] * imageParams.value.number

tokenUsage.value =
tokenUnit.value === 'TK' ? cost : Number((cost * 0.0002).toFixed(3))

return
}
// 角色描述字符数
Expand All @@ -34,22 +35,20 @@ watch([textAreaValue, isMemory], async () => {
memoryList.map((item) => item.content).join('')
)

tokenUsage.value = textAreaTokens + roleTokens + memoryTokens
const cost = textAreaTokens + roleTokens + memoryTokens

tokenUsage.value = tokenUnit.value === 'TK' ? cost : Number(cost.toFixed(3))
})

const showTipsToUsage = () => {
let tipStr =
const tipStr =
currentSession.value?.type === 'image'
? '图像模式:'
: isMemory.value
? '记忆模式:'
: ''
return tipStr + '预计消耗'
}
const getUnit = () => {
const typeList: (string | undefined)[] = ['image', 'voice']
return typeList.includes(currentSession.value?.type) ? '$' : 'TK'
}
</script>

<template>
Expand All @@ -64,9 +63,8 @@ const getUnit = () => {
content="已超出 token 最大阈值"
>
<span :class="tokenExceed ? 'text-[rgb(var(--danger-6))]' : 'mark'">
{{ tokenUsage }}
{{ tokenUsage }} {{ tokenUnit }}
</span>
</a-tooltip>
{{ getUnit() }}
</div>
</template>
16 changes: 9 additions & 7 deletions src/components/Session/components/SessionAvatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defineProps<{ data: SessionData }>()
const roleStore = useRoleStore()
const { updateRole } = roleStore
const { currentRole } = storeToRefs(roleStore)
const { uuid, isTokenUsage } = storeToRefs(useSettingsStore())
const { uuid, isTokenUsage, tokenUnit } = storeToRefs(useSettingsStore())
const { sessionDataList, currentSession } = storeToRefs(useSessionStore())

const { modalMaskStyle } = useModalStyle()
Expand Down Expand Up @@ -50,12 +50,14 @@ const calcToken = (data: SessionData) => {
}

if (data.is_ask) {
return `${roleToken + contentToken + memoryToken}TK${
data.is_memory ? '*' : ''
}`
const token = roleToken + contentToken + memoryToken

return `${tokenUnit.value === 'TK' ? token : Number(token.toFixed(3))}${
tokenUnit.value
}${data.is_memory ? '*' : ''}`
}

return `${contentToken}TK`
return contentToken + tokenUnit.value
}

if (currentSession.value?.type === 'image') {
Expand All @@ -74,11 +76,11 @@ const calcToken = (data: SessionData) => {

<template>
<div class="flex flex-col items-center gap-1">
<Avatar class="w-12!" :value="uuid" v-if="data.is_ask" />
<Avatar class="w-13!" :value="uuid" v-if="data.is_ask" />

<a-tooltip content="点我编辑角色信息" position="tl" v-else>
<Avatar
class="w-12! cursor-pointer"
class="w-13! cursor-pointer"
:value="currentRole?.name"
@click="visible = true"
/>
Expand Down
6 changes: 5 additions & 1 deletion src/components/Session/components/SessionContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ const position = computed(() => (props.data.is_ask ? 'left' : 'right'))
<div
class="copy"
:id="`copy-${data.id}`"
@click="copyText($event, { content: data.message.content })"
@click="
copyText($event, {
content: data.message.content?.prompt || data.message.content
})
"
></div>
</a-tooltip>

Expand Down
6 changes: 5 additions & 1 deletion src/components/Settings/components/Modal.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
const { apiKey, isMemory, modalParams, isTokenUsage } = storeToRefs(
const { apiKey, isMemory, modalParams, isTokenUsage, tokenUnit } = storeToRefs(
useSettingsStore()
)

Expand Down Expand Up @@ -46,6 +46,10 @@ watch(
<li>
<i>Token 用量:</i>
<a-switch v-model="isTokenUsage" type="round" />
<a-radio-group type="button" v-model="tokenUnit">
<a-radio value="TK">Token</a-radio>
<a-radio value="¢">美分(¢)</a-radio>
</a-radio-group>
</li>

<li>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Update/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ onMounted(() => {
<span>更新时间:{{ getLocalTime(updateManifest.date) }}</span>
<span
>更新详情:<a
href="https://github.com/bilibili-ayang/ChatGPT-Desktop/releases/latest"
href="https://github.com/Synaptrix/ChatGPT-Desktop/releases/latest"
>Github</a
></span
>
Expand Down
17 changes: 11 additions & 6 deletions src/stores/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { register, unregisterAll } from '@tauri-apps/api/globalShortcut'
import { appWindow } from '@tauri-apps/api/window'
import { enable, disable } from 'tauri-plugin-autostart-api'
import { nanoid } from 'nanoid'
import type { THEME_MODE } from '@/types'
import type { ThemeMode, TokenUnit } from '@/types'

export const useSettingsStore = defineStore(
'settingsStore',
() => {
// 主题
const themeMode = ref<THEME_MODE>('system')
const themeMode = ref<ThemeMode>('system')

// 用户的唯一值
const uuid = ref('')
Expand Down Expand Up @@ -42,8 +42,11 @@ export const useSettingsStore = defineStore(
// modal设置参数
const modalParams = reactive({ temperature: 0.6, max_tokens: 2000 })

// token 用量
// token
// 用量
const isTokenUsage = ref(false)
// 单位
const tokenUnit = ref<TokenUnit>('TK')

// 绑定快捷键
const registerKey = async () => {
Expand All @@ -65,9 +68,9 @@ export const useSettingsStore = defineStore(
}

// 切换主题
const toggleTheme = async (theme: THEME_MODE = themeMode.value) => {
const toggleTheme = async (theme: ThemeMode = themeMode.value) => {
if (theme === 'system') {
theme = (await appWindow.theme()) as THEME_MODE
theme = (await appWindow.theme()) as ThemeMode
}

document.body.setAttribute('arco-theme', theme)
Expand Down Expand Up @@ -133,6 +136,7 @@ export const useSettingsStore = defineStore(
proxy,
modalParams,
isTokenUsage,
tokenUnit,
toggleTheme
}
},
Expand All @@ -148,7 +152,8 @@ export const useSettingsStore = defineStore(
'isRememberPosition',
'proxy',
'modalParams',
'isTokenUsage'
'isTokenUsage',
'tokenUnit'
]
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/types/shared.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export type THEME_MODE = 'light' | 'dark' | 'system'
export type ThemeMode = 'light' | 'dark' | 'system'

export type REQUEST_HOST = 'OPENAI' | 'GITHUB'
export type RequestHost = 'OPENAI' | 'GITHUB'

export type SAVE_TYPE = 'system' | 'image' | 'markdown'
export type SaveType = 'system' | 'image' | 'markdown'

export type TokenUnit = 'TK' | '¢'
6 changes: 5 additions & 1 deletion src/utils/getMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ const tokenizer = new GPT3Tokenizer({ type: 'gpt3' })
* @param str 需要估算的字符串
*/
export function estimateTokens(str: string): number {
const { tokenUnit } = useSettingsStore()

const encoded: { bpe: number[]; text: string[] } = tokenizer.encode(str)
return encoded.bpe.length
const length = encoded.bpe.length

return tokenUnit === 'TK' ? length : Number((length * 0.0002).toFixed(3))
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/utils/saveImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '@tauri-apps/api/fs'
import { appConfigDir, sep } from '@tauri-apps/api/path'
import html2canvas from 'html2canvas'
import type { SAVE_TYPE } from '@/types'
import type { SaveType } from '@/types'

/**
* 下载图片
Expand Down Expand Up @@ -77,7 +77,7 @@ export const saveImageFromFile = async (file: string) => {

const writeImage = async (
buffer: number[] | ArrayBuffer,
type: SAVE_TYPE,
type: SaveType,
fileName?: string
) => {
const uint8Array = new Uint8Array(buffer)
Expand Down