Skip to content
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
22 changes: 15 additions & 7 deletions src/main/presenter/githubCopilotDeviceFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,13 +591,12 @@ export class GitHubCopilotDeviceFlow {
}

// GitHub Copilot Device Flow configuration
export function createGitHubCopilotDeviceFlow(): GitHubCopilotDeviceFlow {
// Read GitHub OAuth configuration from environment variables
const clientId = import.meta.env.VITE_GITHUB_CLIENT_ID
export function createGitHubCopilotDeviceFlow(clientIdOverride?: string): GitHubCopilotDeviceFlow {
const clientId = clientIdOverride?.trim() || import.meta.env.VITE_GITHUB_CLIENT_ID

if (!clientId) {
throw new Error(
'VITE_GITHUB_CLIENT_ID environment variable is required. Please create a .env file with your GitHub OAuth Client ID.'
'GitHub Client ID is required. Please enter it in the Copilot settings input or set VITE_GITHUB_CLIENT_ID in .env.'
)
}

Expand All @@ -618,10 +617,18 @@ export function createGitHubCopilotDeviceFlow(): GitHubCopilotDeviceFlow {
* 创建一个全局的 GitHub Copilot Device Flow 实例
*/
let globalDeviceFlowInstance: GitHubCopilotDeviceFlow | null = null
let globalDeviceFlowClientId: string | null = null

export function getGlobalGitHubCopilotDeviceFlow(): GitHubCopilotDeviceFlow {
if (!globalDeviceFlowInstance) {
globalDeviceFlowInstance = createGitHubCopilotDeviceFlow()
export function getGlobalGitHubCopilotDeviceFlow(
clientIdOverride?: string
): GitHubCopilotDeviceFlow {
const effectiveClientId = clientIdOverride?.trim() || import.meta.env.VITE_GITHUB_CLIENT_ID

if (!globalDeviceFlowInstance || globalDeviceFlowClientId !== effectiveClientId) {
globalDeviceFlowInstance?.dispose()
globalDeviceFlowInstance = null
globalDeviceFlowInstance = createGitHubCopilotDeviceFlow(effectiveClientId)
globalDeviceFlowClientId = effectiveClientId || null
}
return globalDeviceFlowInstance
}
Expand All @@ -631,4 +638,5 @@ export function disposeGlobalGitHubCopilotDeviceFlow(): void {
globalDeviceFlowInstance.dispose()
globalDeviceFlowInstance = null
}
globalDeviceFlowClientId = null
}
7 changes: 4 additions & 3 deletions src/main/presenter/githubCopilotOAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,15 +221,16 @@ export class GitHubCopilotOAuth {
}

// GitHub Copilot OAuth configuration
export function createGitHubCopilotOAuth(): GitHubCopilotOAuth {
export function createGitHubCopilotOAuth(clientIdOverride?: string): GitHubCopilotOAuth {
// Read GitHub OAuth configuration from environment variables
const clientId = import.meta.env.VITE_GITHUB_CLIENT_ID
const clientId = clientIdOverride?.trim() || import.meta.env.VITE_GITHUB_CLIENT_ID
const clientSecret = import.meta.env.VITE_GITHUB_CLIENT_SECRET
const redirectUri =
import.meta.env.VITE_GITHUB_REDIRECT_URI || 'https://deepchatai.cn/auth/github/callback'

console.log('GitHub OAuth Configuration:')
console.log('- Client ID configured:', clientId ? '✅' : '❌')
console.log('- Client ID override provided:', clientIdOverride ? '✅' : '❌')
console.log('- Client Secret configured:', clientSecret ? '✅' : '❌')
console.log('- Redirect URI:', redirectUri)
console.log('- Environment variables check:')
Expand All @@ -248,7 +249,7 @@ export function createGitHubCopilotOAuth(): GitHubCopilotOAuth {

if (!clientId) {
throw new Error(
'GITHUB_CLIENT_ID environment variable is required. Please create a .env file with your GitHub OAuth Client ID. You can use either GITHUB_CLIENT_ID or VITE_GITHUB_CLIENT_ID.'
'GitHub Client ID is required. Please enter it in the Copilot settings input or set GITHUB_CLIENT_ID / VITE_GITHUB_CLIENT_ID in .env.'
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class GithubCopilotProvider extends BaseLLMProvider {
if (this.provider.enable) {
try {
this.isInitialized = true
this.deviceFlow = getGlobalGitHubCopilotDeviceFlow()
this.deviceFlow = getGlobalGitHubCopilotDeviceFlow(this.provider.copilotClientId)

// 检查现有认证状态
if (this.provider.apiKey) {
Expand Down
6 changes: 3 additions & 3 deletions src/main/presenter/oauthPresenter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export class OAuthPresenter {
*/
async startGitHubCopilotDeviceFlowLogin(providerId: string): Promise<boolean> {
try {
const githubDeviceFlow = getGlobalGitHubCopilotDeviceFlow()
const provider = presenter.configPresenter.getProviderById(providerId)
const githubDeviceFlow = getGlobalGitHubCopilotDeviceFlow(provider?.copilotClientId)

// 首先检查现有认证状态
if (provider && provider.apiKey) {
Expand Down Expand Up @@ -97,7 +97,8 @@ export class OAuthPresenter {

// 使用专门的GitHub Copilot OAuth实现
console.log('[GitHub Copilot][OAuth] Creating GitHub OAuth instance...')
const githubOAuth = createGitHubCopilotOAuth()
const provider = presenter.configPresenter.getProviderById(providerId)
const githubOAuth = createGitHubCopilotOAuth(provider?.copilotClientId)

// 开始OAuth登录
console.log('[GitHub Copilot][OAuth] Starting OAuth login flow...')
Expand Down Expand Up @@ -137,7 +138,6 @@ export class OAuthPresenter {

// 保存访问令牌到provider配置
console.log('[GitHub Copilot][OAuth] Saving access token to provider configuration...')
const provider = presenter.configPresenter.getProviderById(providerId)
if (provider) {
provider.apiKey = accessToken
presenter.configPresenter.setProviderById(providerId, provider)
Expand Down
45 changes: 44 additions & 1 deletion src/renderer/settings/components/GitHubCopilotOAuth.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@
{{ t('settings.provider.githubCopilotAuth') }}
</Label>

<div class="w-full space-y-1">
<Label :for="`${provider.id}-copilot-client-id`" class="text-xs text-muted-foreground">
{{ t('settings.provider.githubCopilotClientId') }}
</Label>
<Input
:id="`${provider.id}-copilot-client-id`"
:model-value="copilotClientId"
:placeholder="t('settings.provider.githubCopilotClientId')"
@update:model-value="copilotClientId = String($event)"
@blur="handleClientIdBlur"
@keyup.enter="saveClientId(copilotClientId)"
/>
<div class="text-xs text-muted-foreground">
{{ t('settings.provider.githubCopilotClientIdHint') }}
</div>
</div>

<!-- 如果已经有Token -->
<div v-if="hasToken" class="w-full space-y-2">
<div
Expand Down Expand Up @@ -116,6 +133,7 @@
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { Label } from '@shadcn/components/ui/label'
import { Input } from '@shadcn/components/ui/input'
import { Button } from '@shadcn/components/ui/button'
import { Icon } from '@iconify/vue'
import { usePresenter } from '@/composables/usePresenter'
Expand All @@ -140,12 +158,37 @@ const modelCheckStore = useModelCheckStore()

const isLoggingIn = ref(false)
const validationResult = ref<{ success: boolean; message: string } | null>(null)
const copilotClientId = ref(props.provider.copilotClientId || '')

const hasToken = computed(() => {
return !!(props.provider.apiKey && props.provider.apiKey.trim())
})

// 注意:GitHub Copilot OAuth配置现在从环境变量读取
watch(
() => props.provider,
(next) => {
copilotClientId.value = next.copilotClientId || ''
}
)

const saveClientId = async (value: string) => {
const next = value.trim()
copilotClientId.value = next
try {
await providerStore.updateProviderConfig(props.provider.id, { copilotClientId: next })
} catch (error) {
const message = error instanceof Error ? error.message : t('settings.provider.loginFailed')
validationResult.value = { success: false, message }
}
}

const handleClientIdBlur = (event: FocusEvent) => {
const target = event.target as HTMLInputElement | null
if (!target) return
void saveClientId(target.value)
}

// 默认从环境变量读取,可在上方自定义 Client ID

/**
* 开始Device Flow登录流程(推荐)
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/da-DK/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@
"githubCopilotNotConnected": "GitHub Copilot ikke forbundet",
"loginWithGitHub": "Log ind med GitHub",
"loggingIn": "Logger ind...",
"githubCopilotClientId": "Custom Client ID",
"githubCopilotClientIdHint": "Optional. Leave empty to use the built-in default Client ID. Only affects GitHub Copilot auth.",
"githubCopilotLoginTip": "Giv DeepChat adgang til dit GitHub Copilot-abonnement. Rettighederne 'read:user' og 'read:org' er nødvendige for Copilot API'et.",
"loginSuccess": "Login lykkedes",
"loginFailed": "Login mislykkedes",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/en-US/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "GitHub Copilot Not Connected",
"loginWithGitHub": "Login with GitHub",
"loggingIn": "Logging in...",
"githubCopilotClientId": "Custom Client ID",
"githubCopilotClientIdHint": "Optional. Leave empty to use the built-in default Client ID. Only affects GitHub Copilot auth.",
"githubCopilotLoginTip": "Authorize DeepChat to access your GitHub Copilot subscription. 'read:user' and 'read:org' permissions are required to access the Copilot API.",
"loginSuccess": "Login successful",
"loginFailed": "Login failed",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/fa-IR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "گیت‌هاب کوپایلت پیوند داده نشده",
"loginWithGitHub": "ورود با گیت‌هاب",
"loggingIn": "در حال ورود...",
"githubCopilotClientId": "Custom Client ID",
"githubCopilotClientIdHint": "Optional. Leave empty to use the built-in default Client ID. Only affects GitHub Copilot auth.",
"githubCopilotLoginTip": "دیپ‌چت را برای دسترسی به اشتراک گیت‌هاب کوپایلت خود مجاز کنید. دسترسی‌های 'read:user' و 'read:org' برای دسترسی به API کوپایلت لازم است.",
"loginSuccess": "ورود موفق",
"loginFailed": "ورود ناموفق",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/fr-FR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "GitHub Copilot non connecté",
"loginWithGitHub": "Se connecter avec GitHub",
"loggingIn": "Connexion en cours...",
"githubCopilotClientId": "Custom Client ID",
"githubCopilotClientIdHint": "Optional. Leave empty to use the built-in default Client ID. Only affects GitHub Copilot auth.",
"githubCopilotLoginTip": "Autorisez DeepChat à accéder à votre abonnement GitHub Copilot. Les autorisations 'read:user' et 'read:org' sont requises pour accéder à l'API Copilot.",
"loginSuccess": "Connexion réussie",
"loginFailed": "Échec de la connexion",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/he-IL/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "GitHub Copilot אינו מחובר",
"loginWithGitHub": "התחבר עם GitHub",
"loggingIn": "מתחבר...",
"githubCopilotClientId": "Custom Client ID",
"githubCopilotClientIdHint": "Optional. Leave empty to use the built-in default Client ID. Only affects GitHub Copilot auth.",
"githubCopilotLoginTip": "אשר ל-DeepChat לגשת למנוי GitHub Copilot שלך. ההרשאות 'read:user' ו-'read:org' נדרשות כדי לגשת ל-API של Copilot.",
"loginSuccess": "ההתחברות הצליחה",
"loginFailed": "ההתחברות נכשלה",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/ja-JP/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "GitHub Copilot未接続",
"loginWithGitHub": "GitHubでログイン",
"loggingIn": "ログイン中...",
"githubCopilotClientId": "Custom Client ID",
"githubCopilotClientIdHint": "Optional. Leave empty to use the built-in default Client ID. Only affects GitHub Copilot auth.",
"githubCopilotLoginTip": "DeepChatがGitHub Copilotサブスクリプションにアクセスすることを許可します。Copilot APIにアクセスするには'read:user'と'read:org'の権限が必要です。",
"loginSuccess": "ログイン成功",
"loginFailed": "ログイン失敗",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/ko-KR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "GitHub Copilot 연결되지 않음",
"loginWithGitHub": "GitHub로 로그인",
"loggingIn": "로그인 중...",
"githubCopilotClientId": "Custom Client ID",
"githubCopilotClientIdHint": "Optional. Leave empty to use the built-in default Client ID. Only affects GitHub Copilot auth.",
"githubCopilotLoginTip": "DeepChat이 GitHub Copilot 구독에 액세스하도록 허용하세요. Copilot API에 액세스하려면 'read:user' 및 'read:org' 권한이 필요합니다.",
"loginSuccess": "로그인 성공",
"loginFailed": "로그인 실패",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/pt-BR/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "GitHub Copilot Não Conectado",
"loginWithGitHub": "Entrar com GitHub",
"loggingIn": "Entrando...",
"githubCopilotClientId": "Custom Client ID",
"githubCopilotClientIdHint": "Optional. Leave empty to use the built-in default Client ID. Only affects GitHub Copilot auth.",
"githubCopilotLoginTip": "Autorize o DeepChat a acessar sua assinatura do GitHub Copilot. As permissões 'read:user' e 'read:org' são necessárias para acessar a API do Copilot.",
"loginSuccess": "Login bem-sucedido",
"loginFailed": "Falha no login",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/ru-RU/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "GitHub Copilot не подключен",
"loginWithGitHub": "Войти через GitHub",
"loggingIn": "Вход...",
"githubCopilotClientId": "Custom Client ID",
"githubCopilotClientIdHint": "Optional. Leave empty to use the built-in default Client ID. Only affects GitHub Copilot auth.",
Comment on lines +413 to +414
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Translation values are in English, not Russian.

The keys githubCopilotClientId and githubCopilotClientIdHint have English values instead of Russian translations. For consistency with the rest of the file, these should be translated.

Suggested Russian translations:

  • githubCopilotClientId: "Пользовательский Client ID"
  • githubCopilotClientIdHint: "Необязательно. Оставьте пустым для использования встроенного Client ID по умолчанию. Влияет только на авторизацию GitHub Copilot."
🤖 Prompt for AI Agents
In src/renderer/src/i18n/ru-RU/settings.json around lines 413 to 414, the values
for githubCopilotClientId and githubCopilotClientIdHint are in English; replace
them with the provided Russian translations: set githubCopilotClientId to
"Пользовательский Client ID" and githubCopilotClientIdHint to "Необязательно.
Оставьте пустым для использования встроенного Client ID по умолчанию. Влияет
только на авторизацию GitHub Copilot.", preserving the JSON key names and
quoting/escaping exactly as the surrounding entries.

"githubCopilotLoginTip": "Разрешите DeepChat доступ к вашей подписке GitHub Copilot. Для доступа к API Copilot требуются разрешения 'read:user' и 'read:org'.",
"loginSuccess": "Вход выполнен успешно",
"loginFailed": "Ошибка входа",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/zh-CN/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,8 @@
"githubCopilotNotConnected": "GitHub Copilot 未连接",
"loginWithGitHub": "使用 GitHub 登录",
"loggingIn": "登录中...",
"githubCopilotClientId": "自定义 Client ID",
"githubCopilotClientIdHint": "可选,留空使用默认 Client ID,仅影响 GitHub Copilot 授权。",
"githubCopilotLoginTip": "点击授权 DeepChat 访问您的 GitHub Copilot 订阅",
"loginSuccess": "登录成功",
"loginFailed": "登录失败",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/zh-HK/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "GitHub Copilot 未連接",
"loginWithGitHub": "用 GitHub 登入",
"loggingIn": "登入中...",
"githubCopilotClientId": "自訂 Client ID",
"githubCopilotClientIdHint": "可選,留空會使用預設 Client ID,只影響 GitHub Copilot 授權。",
"githubCopilotLoginTip": "請授權 DeepChat 存取你的 GitHub Copilot 訂閱。需要 'read:user' 及 'read:org' 權限才能正常使用 Copilot API。",
"loginSuccess": "登入成功",
"loginFailed": "登入失敗",
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/src/i18n/zh-TW/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@
"githubCopilotNotConnected": "GitHub Copilot 未連接",
"loginWithGitHub": "使用 GitHub 登入",
"loggingIn": "登入中...",
"githubCopilotClientId": "自訂 Client ID",
"githubCopilotClientIdHint": "可選,留空會使用預設 Client ID,只影響 GitHub Copilot 授權。",
"githubCopilotLoginTip": "請授權 DeepChat 訪問您的 GitHub Copilot 訂閱。需要 'read:user' 和 'read:org' 權限才能正常使用 Copilot API。",
"loginSuccess": "登入成功",
"loginFailed": "登入失敗",
Expand Down
1 change: 1 addition & 0 deletions src/shared/provider-operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface ProviderChange {
export const REBUILD_REQUIRED_FIELDS = [
'enable',
'apiKey',
'copilotClientId',
'baseUrl',
'authMode',
'oauthToken',
Expand Down
1 change: 1 addition & 0 deletions src/shared/types/presenters/legacy.presenters.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ export type LLM_PROVIDER = {
name: string
apiType: string
apiKey: string
copilotClientId?: string
baseUrl: string
enable: boolean
custom?: boolean
Expand Down
1 change: 1 addition & 0 deletions src/shared/types/presenters/llmprovider.presenter.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type LLM_PROVIDER = {
name: string
apiType: string
apiKey: string
copilotClientId?: string
baseUrl: string
models: MODEL_META[]
customModels?: MODEL_META[]
Expand Down
2 changes: 2 additions & 0 deletions src/types/i18n.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,8 @@ declare module 'vue-i18n' {
githubCopilotNotConnected: string
loginWithGitHub: string
loggingIn: string
githubCopilotClientId: string
githubCopilotClientIdHint: string
githubCopilotLoginTip: string
loginSuccess: string
loginFailed: string
Expand Down