mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-22 09:01:45 +03:00
Allow AI use without user and update settings to match
This commit is contained in:
parent
fcd4e616ac
commit
ef8734d638
@ -89,6 +89,35 @@ export class AIService {
|
||||
private cloud: ReturnType<typeof getCloudApiClient>
|
||||
) {}
|
||||
|
||||
async configurationValid(userToken?: string) {
|
||||
const modelKind = await this.gitConfig.getWithDefault<ModelKind>(
|
||||
GitAIConfigKey.ModelProvider,
|
||||
ModelKind.OpenAI
|
||||
);
|
||||
const openAIKeyOption = await this.gitConfig.getWithDefault<KeyOption>(
|
||||
GitAIConfigKey.OpenAIKeyOption,
|
||||
KeyOption.ButlerAPI
|
||||
);
|
||||
const openAIKey = await this.gitConfig.get(GitAIConfigKey.OpenAIKey);
|
||||
const anthropicKeyOption = await this.gitConfig.getWithDefault<KeyOption>(
|
||||
GitAIConfigKey.AnthropicKeyOption,
|
||||
KeyOption.ButlerAPI
|
||||
);
|
||||
const anthropicKey = await this.gitConfig.get(GitAIConfigKey.AnthropicKey);
|
||||
|
||||
if (
|
||||
(modelKind == ModelKind.OpenAI && openAIKeyOption == KeyOption.ButlerAPI) ||
|
||||
(modelKind == ModelKind.Anthropic && anthropicKeyOption == KeyOption.ButlerAPI)
|
||||
) {
|
||||
return Boolean(userToken);
|
||||
}
|
||||
|
||||
return Boolean(
|
||||
(modelKind == ModelKind.OpenAI && openAIKey) ||
|
||||
(modelKind == ModelKind.Anthropic && anthropicKey)
|
||||
);
|
||||
}
|
||||
|
||||
// This optionally returns a summarizer. There are a few conditions for how this may occur
|
||||
// Firstly, if the user has opted to use the GB API and isn't logged in, it will return undefined
|
||||
// Secondly, if the user has opted to bring their own key but hasn't provided one, it will return undefined
|
||||
|
@ -2,6 +2,7 @@
|
||||
import Select from './Select.svelte';
|
||||
import SelectItem from './SelectItem.svelte';
|
||||
import TextBox from './TextBox.svelte';
|
||||
import WelcomeSigninAction from './WelcomeSigninAction.svelte';
|
||||
import {
|
||||
AnthropicModelName,
|
||||
GitAIConfigKey,
|
||||
@ -12,10 +13,13 @@
|
||||
import { GitConfigService } from '$lib/backend/gitConfigService';
|
||||
import RadioButton from '$lib/components/RadioButton.svelte';
|
||||
import SectionCard from '$lib/components/SectionCard.svelte';
|
||||
import { UserService } from '$lib/stores/user';
|
||||
import { getContextByClass } from '$lib/utils/context';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const gitConfigService = getContextByClass(GitConfigService);
|
||||
const userService = getContextByClass(UserService);
|
||||
const user = userService.user;
|
||||
|
||||
let modelKind: ModelKind;
|
||||
let openAIKeyOption: KeyOption;
|
||||
@ -166,6 +170,8 @@
|
||||
{item.name}
|
||||
</SelectItem>
|
||||
</Select>
|
||||
{:else if !$user}
|
||||
<WelcomeSigninAction prompt="A user is required to make use of the GitButler API" />
|
||||
{/if}
|
||||
</div>
|
||||
</SectionCard>
|
||||
@ -219,6 +225,8 @@
|
||||
{item.name}
|
||||
</SelectItem>
|
||||
</Select>
|
||||
{:else if !$user}
|
||||
<WelcomeSigninAction prompt="A user is required to make use of the GitButler API" />
|
||||
{/if}
|
||||
</div>
|
||||
</SectionCard>
|
||||
|
@ -113,7 +113,7 @@
|
||||
generateBranchName();
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
onMount(async () => {
|
||||
laneWidth = lscache.get(laneWidthKey + branch.id);
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { AIService } from '$lib/backend/aiService';
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import Modal from '$lib/components/Modal.svelte';
|
||||
import TextBox from '$lib/components/TextBox.svelte';
|
||||
@ -6,10 +7,12 @@
|
||||
import ContextMenuItem from '$lib/components/contextmenu/ContextMenuItem.svelte';
|
||||
import ContextMenuSection from '$lib/components/contextmenu/ContextMenuSection.svelte';
|
||||
import { projectAiGenEnabled } from '$lib/config/config';
|
||||
import { UserService } from '$lib/stores/user';
|
||||
import { normalizeBranchName } from '$lib/utils/branch';
|
||||
import { getContextByClass } from '$lib/utils/context';
|
||||
import { BranchController } from '$lib/vbranches/branchController';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import type { User } from '$lib/backend/cloud';
|
||||
import type { Branch } from '$lib/vbranches/types';
|
||||
|
||||
export let branch: Branch;
|
||||
@ -18,6 +21,9 @@
|
||||
export let isUnapplied = false;
|
||||
|
||||
const branchController = getContextByClass(BranchController);
|
||||
const aiService = getContextByClass(AIService);
|
||||
const userService = getContextByClass(UserService);
|
||||
const user = userService.user;
|
||||
|
||||
let deleteBranchModal: Modal;
|
||||
let renameRemoteModal: Modal;
|
||||
@ -32,6 +38,14 @@
|
||||
$: commits = branch.commits;
|
||||
$: hasIntegratedCommits =
|
||||
commits.length > 0 ? commits.some((c) => c.status == 'integrated') : false;
|
||||
|
||||
let aiConfigurationValid = false;
|
||||
|
||||
$: setAIConfigurationValid($user);
|
||||
|
||||
async function setAIConfigurationValid(user: User | undefined) {
|
||||
aiConfigurationValid = await aiService.configurationValid(user?.access_token);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if visible}
|
||||
@ -69,7 +83,10 @@
|
||||
dispatch('action', 'generate-branch-name');
|
||||
visible = false;
|
||||
}}
|
||||
disabled={isUnapplied || !$aiGenEnabled || branch.files?.length == 0 || !branch.active}
|
||||
disabled={isUnapplied ||
|
||||
!($aiGenEnabled && aiConfigurationValid) ||
|
||||
branch.files?.length == 0 ||
|
||||
!branch.active}
|
||||
/>
|
||||
</ContextMenuSection>
|
||||
<ContextMenuSection>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import SectionCard from './SectionCard.svelte';
|
||||
import WelcomeSigninAction from './WelcomeSigninAction.svelte';
|
||||
import { getCloudApiClient } from '$lib/backend/cloud';
|
||||
import Link from '$lib/components/Link.svelte';
|
||||
import Spacer from '$lib/components/Spacer.svelte';
|
||||
import Toggle from '$lib/components/Toggle.svelte';
|
||||
import WelcomeSigninAction from '$lib/components/WelcomeSigninAction.svelte';
|
||||
import { projectAiGenEnabled } from '$lib/config/config';
|
||||
import { projectAiGenAutoBranchNamingEnabled } from '$lib/config/config';
|
||||
import { UserService } from '$lib/stores/user';
|
||||
@ -62,69 +62,77 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $user}
|
||||
<div class="aigen-wrap">
|
||||
<SectionCard labelFor="aiGenEnabled" on:click={aiGenToggle} orientation="row">
|
||||
<svelte:fragment slot="title">Enable branch and commit message generation</svelte:fragment>
|
||||
<svelte:fragment slot="caption">
|
||||
Uses OpenAI's API. If enabled, diffs will sent to OpenAI's servers when pressing the
|
||||
"Generate message" button.
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<Toggle id="aiGenEnabled" checked={$aiGenEnabled} on:change={aiGenToggle} />
|
||||
</svelte:fragment>
|
||||
</SectionCard>
|
||||
|
||||
<SectionCard
|
||||
labelFor="branchNameGen"
|
||||
disabled={!$aiGenEnabled}
|
||||
on:click={aiGenBranchNamesToggle}
|
||||
orientation="row"
|
||||
>
|
||||
<svelte:fragment slot="title">Automatically generate branch names</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<Toggle
|
||||
id="branchNameGen"
|
||||
disabled={!$aiGenEnabled}
|
||||
checked={$aiGenAutoBranchNamingEnabled}
|
||||
on:change={aiGenBranchNamesToggle}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</SectionCard>
|
||||
</div>
|
||||
{#if !$user}
|
||||
<WelcomeSigninAction />
|
||||
|
||||
<Spacer />
|
||||
{/if}
|
||||
|
||||
{#if $user.role === 'admin'}
|
||||
<h3 class="text-base-15 text-bold">Full data synchronization</h3>
|
||||
<div class="aigen-wrap">
|
||||
<h3 class="text-base-15 text-bold">AI Options</h3>
|
||||
<p class="text-base-body-12">
|
||||
GitButler supports the use of OpenAI and Anthropic to provide commit message and branch name
|
||||
generation. This works either through GitButler's API or in a bring your own key configuration
|
||||
and can be configured in the main preferences screen.
|
||||
</p>
|
||||
|
||||
<SectionCard labelFor="historySync" on:change={(e) => onSyncChange(e.detail)} orientation="row">
|
||||
<svelte:fragment slot="caption">
|
||||
Sync my history, repository and branch data for backup, sharing and team features.
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<Toggle
|
||||
id="historySync"
|
||||
checked={project.api?.sync || false}
|
||||
on:change={(e) => onSyncChange(e.detail)}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</SectionCard>
|
||||
<SectionCard labelFor="aiGenEnabled" on:click={aiGenToggle} orientation="row">
|
||||
<svelte:fragment slot="title">Enable branch and commit message generation</svelte:fragment>
|
||||
<svelte:fragment slot="caption">
|
||||
If enabled, diffs will sent to OpenAI or Anthropic's servers when pressing the "Generate
|
||||
message" and "Generate branch name" button.
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<Toggle id="aiGenEnabled" checked={$aiGenEnabled} on:change={aiGenToggle} />
|
||||
</svelte:fragment>
|
||||
</SectionCard>
|
||||
|
||||
{#if project.api}
|
||||
<div class="api-link">
|
||||
<Link
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="{PUBLIC_API_BASE_URL}projects/{project.api?.repository_id}"
|
||||
>Go to GitButler Cloud Project</Link
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
<Spacer />
|
||||
<SectionCard
|
||||
labelFor="branchNameGen"
|
||||
disabled={!$aiGenEnabled}
|
||||
on:click={aiGenBranchNamesToggle}
|
||||
orientation="row"
|
||||
>
|
||||
<svelte:fragment slot="title">Automatically generate branch names</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<Toggle
|
||||
id="branchNameGen"
|
||||
disabled={!$aiGenEnabled}
|
||||
checked={$aiGenAutoBranchNamingEnabled}
|
||||
on:change={aiGenBranchNamesToggle}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</SectionCard>
|
||||
</div>
|
||||
|
||||
<Spacer />
|
||||
|
||||
{#if $user?.role === 'admin'}
|
||||
<h3 class="text-base-15 text-bold">Full data synchronization</h3>
|
||||
|
||||
<SectionCard labelFor="historySync" on:change={(e) => onSyncChange(e.detail)} orientation="row">
|
||||
<svelte:fragment slot="caption">
|
||||
Sync my history, repository and branch data for backup, sharing and team features.
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<Toggle
|
||||
id="historySync"
|
||||
checked={project.api?.sync || false}
|
||||
on:change={(e) => onSyncChange(e.detail)}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</SectionCard>
|
||||
|
||||
{#if project.api}
|
||||
<div class="api-link">
|
||||
<Link
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="{PUBLIC_API_BASE_URL}projects/{project.api?.repository_id}"
|
||||
>Go to GitButler Cloud Project</Link
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<WelcomeSigninAction />
|
||||
<Spacer />
|
||||
{/if}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
import { setAutoHeight } from '$lib/utils/useAutoHeight';
|
||||
import { useResize } from '$lib/utils/useResize';
|
||||
import { BranchController } from '$lib/vbranches/branchController';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { createEventDispatcher, onMount } from 'svelte';
|
||||
import { quintOut } from 'svelte/easing';
|
||||
import { fly, slide } from 'svelte/transition';
|
||||
import type { User } from '$lib/backend/cloud';
|
||||
@ -135,6 +135,12 @@
|
||||
descriptionTextArea.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
let aiConfigurationValid = false;
|
||||
|
||||
onMount(async () => {
|
||||
aiConfigurationValid = await aiService.configurationValid(user?.access_token);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="commit-box" class:commit-box__expanded={$expanded}>
|
||||
@ -212,15 +218,15 @@
|
||||
|
||||
<div
|
||||
class="commit-box__texarea-actions"
|
||||
use:tooltip={$aiGenEnabled && user
|
||||
use:tooltip={$aiGenEnabled && aiConfigurationValid
|
||||
? ''
|
||||
: 'You must be logged in and have summary generation enabled to use this feature'}
|
||||
: 'You must be logged in or have provided your own API key and have summary generation enabled to use this feature'}
|
||||
>
|
||||
<DropDownButton
|
||||
kind="outlined"
|
||||
icon="ai-small"
|
||||
color="neutral"
|
||||
disabled={!$aiGenEnabled || !user}
|
||||
disabled={!($aiGenEnabled && aiConfigurationValid)}
|
||||
loading={aiLoading}
|
||||
on:click={() => generateCommitMessage(branch.files)}
|
||||
>
|
||||
|
@ -4,6 +4,9 @@
|
||||
import { UserService } from '$lib/stores/user';
|
||||
import { getContextByClass } from '$lib/utils/context';
|
||||
|
||||
export let prompt: string =
|
||||
'Enable GitButler features like automatic branch and commit message generation.';
|
||||
|
||||
const userService = getContextByClass(UserService);
|
||||
const user = userService.user;
|
||||
|
||||
@ -35,8 +38,6 @@
|
||||
<svelte:fragment slot="icon">
|
||||
{@html signinSvg}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="message">
|
||||
Enable GitButler features like automatic branch and commit message generation.
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="message">{prompt}</svelte:fragment>
|
||||
</WelcomeAction>
|
||||
{/if}
|
||||
|
Loading…
Reference in New Issue
Block a user