Allow AI use without user and update settings to match

This commit is contained in:
Caleb Owens 2024-03-18 09:37:33 +00:00 committed by Mattias Granlund
parent fcd4e616ac
commit ef8734d638
7 changed files with 136 additions and 67 deletions

View File

@ -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

View File

@ -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>

View File

@ -113,7 +113,7 @@
generateBranchName();
}
onMount(() => {
onMount(async () => {
laneWidth = lscache.get(laneWidthKey + branch.id);
});

View File

@ -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>

View File

@ -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,13 +62,25 @@
}
</script>
{#if $user}
{#if !$user}
<WelcomeSigninAction />
<Spacer />
{/if}
<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="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.
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} />
@ -95,7 +107,7 @@
<Spacer />
{#if $user.role === 'admin'}
{#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">
@ -123,10 +135,6 @@
{/if}
<Spacer />
{/if}
{:else}
<WelcomeSigninAction />
<Spacer />
{/if}
<style lang="post-css">
.aigen-wrap {

View File

@ -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)}
>

View File

@ -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}