Skip to content

Commit

Permalink
feat: Add models to choose in settings AI AdminCP
Browse files Browse the repository at this point in the history
  • Loading branch information
aXenDeveloper committed Oct 1, 2024
1 parent 14db5a5 commit c92c8ef
Show file tree
Hide file tree
Showing 22 changed files with 205 additions and 44 deletions.
3 changes: 2 additions & 1 deletion apps/backend/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ type LogsAdminEmailObj {
}

type Mutation {
admin__core_ai__edit(key: String, provider: AiProvider!): ShowAdminCoreAiObj!
admin__core_ai__edit(key: String, model: String!, provider: AiProvider!): ShowAdminCoreAiObj!
admin__core_ai__test(prompt: String!): String!
admin__core_authorization_settings__edit(force_login: Boolean!, lock_register: Boolean!, require_confirm_email: Boolean!): ShowAdminAuthorizationSettingsObj!
admin__core_email_settings__edit(color_primary: String!, color_primary_foreground: String!, from: String!, logo: UploadWithKeepCoreFilesArgs, provider: EmailProvider!, resend_key: String, smtp: SMTPEditAdminEmailSettingsService): ShowAdminEmailSettingsServiceObj!
Expand Down Expand Up @@ -365,6 +365,7 @@ type ShowAdminCaptchaSecurityObj {
}

type ShowAdminCoreAiObj {
model: String
provider: AiProvider!
}

Expand Down
2 changes: 2 additions & 0 deletions apps/frontend/src/graphql/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ export type Mutation = {

export type MutationAdmin__Core_Ai__EditArgs = {
key?: InputMaybe<Scalars['String']['input']>;
model: Scalars['String']['input'];
provider: AiProvider;
};

Expand Down Expand Up @@ -873,6 +874,7 @@ export type ShowAdminCaptchaSecurityObj = {

export type ShowAdminCoreAiObj = {
__typename?: 'ShowAdminCoreAiObj';
model?: Maybe<Scalars['String']['output']>;
provider: AiProvider | `${AiProvider}`;
};

Expand Down
1 change: 1 addition & 0 deletions apps/frontend/src/plugins/admin/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@
"title": "OpenAI",
"desc": "Read more on <link>OpenAI - VitNode Docs</link>."
},
"model": "Model",
"provider": "Provider",
"testing": {
"title": "Test Your AI",
Expand Down
3 changes: 3 additions & 0 deletions packages/backend/src/core/admin/ai/edit/edit.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export class EditAdminCoreAiArgs {
@Field(() => String, { nullable: true })
key: null | string;

@Field(() => String)
model: string;

@Field(() => AiProvider)
provider: AiProvider;
}
2 changes: 2 additions & 0 deletions packages/backend/src/core/admin/ai/edit/edit.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class EditAdminCoreAiService extends HelpersCoreAi {
async edit({
provider,
key,
model,
}: EditAdminCoreAiArgs): Promise<ShowAdminCoreAiObj> {
const configSettings = getConfigFile();

Expand All @@ -20,6 +21,7 @@ export class EditAdminCoreAiService extends HelpersCoreAi {
ai: {
...configSettings.ai,
provider,
model,
},
};
await writeFile(configPath, JSON.stringify(newData, null, 2));
Expand Down
3 changes: 3 additions & 0 deletions packages/backend/src/core/admin/ai/show/show.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ registerEnumType(AiProvider, {

@ObjectType()
export class ShowAdminCoreAiObj {
@Field(() => String, { nullable: true })
model?: string;

@Field(() => AiProvider)
provider: AiProvider;
}
4 changes: 3 additions & 1 deletion packages/backend/src/core/admin/ai/show/show.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { ShowAdminCoreAiObj } from './show.dto';
@Injectable()
export class ShowAdminCoreAiService extends HelpersCoreAi {
show(): ShowAdminCoreAiObj {
return this.getAiCredentials();
const data = this.getAiCredentials();

return data;
}
}
57 changes: 48 additions & 9 deletions packages/backend/src/core/ai/provider/ai.service.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,73 @@
import { CustomError } from '@/errors';
import { AiProvider } from '@/providers';
import { createGoogleGenerativeAI } from '@ai-sdk/google';
import { createOpenAI } from '@ai-sdk/openai';
import { Injectable } from '@nestjs/common';
import { generateText, LanguageModel } from 'ai';
import { generateText, LanguageModel, streamText } from 'ai';

import { HelpersCoreAi } from '../ai.helpers';

@Injectable()
export class AiService extends HelpersCoreAi {
private getModel(): LanguageModel {
private getModel(): LanguageModel | undefined {
const aiCredentials = this.getAiCredentials();

if (aiCredentials.provider === AiProvider.none) {
throw new CustomError({
code: 'AI_PROVIDER_NOT_SET',
message: 'AI provider is not set.',
if (aiCredentials.provider === AiProvider.none || !aiCredentials.model) {
return;
}

if (aiCredentials.provider === AiProvider.google) {
const google = createGoogleGenerativeAI({
apiKey: aiCredentials.key,
});

return google(aiCredentials.model);
}

const google = createGoogleGenerativeAI({
const openai = createOpenAI({
apiKey: aiCredentials.key,
});

return google('gemini-1.0-pro');
return openai(aiCredentials.model);
}

async generateText(args: Omit<Parameters<typeof generateText>[0], 'model'>) {
const model = this.getModel();
if (!model) {
throw new CustomError({
code: 'AI_PROVIDER_NOT_SET',
message: 'AI provider is not set.',
});
}

try {
const result = await generateText({
model: this.getModel(),
model,
...args,
});

return result;
} catch (error) {
const err = error as Error;
throw new CustomError({
code: 'AI_ERROR',
message: err.message,
});
}
}

async streamText(args: Omit<Parameters<typeof generateText>[0], 'model'>) {
const model = this.getModel();
if (!model) {
throw new CustomError({
code: 'AI_PROVIDER_NOT_SET',
message: 'AI provider is not set.',
});
}

try {
const result = await streamText({
model,
...args,
});

Expand Down
1 change: 1 addition & 0 deletions packages/backend/src/providers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export enum AiProvider {

export interface ConfigType {
ai: {
model?: string;
provider: AiProvider;
};
editor: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default [
},
{
rules: {
'perfectionist/sort-named-exports': 'warn',
'perfectionist/sort-enums': 'warn',
'perfectionist/sort-exports': 'warn',
'@typescript-eslint/no-dynamic-delete': 'off',
Expand Down
5 changes: 4 additions & 1 deletion packages/frontend/src/components/form/fields/radio-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export function AutoFormRadioGroup<T extends FieldValues>({
className,
childComponent: ChildComponent,
hideOptionalLabel,
overrideOptions,
}: {
componentProps?: AutoFormRadioGroupProps;
} & AutoFormItemProps<T>) {
Expand All @@ -48,7 +49,9 @@ export function AutoFormRadioGroup<T extends FieldValues>({
)._def.values;

let values: [string, string][] = [];
if (!Array.isArray(baseValues)) {
if (overrideOptions?.length) {
values = overrideOptions.map(value => [value, value]);
} else if (!Array.isArray(baseValues)) {
values = Object.entries(baseValues as object);
} else {
values = baseValues.map(value => [value, value]);
Expand Down
9 changes: 7 additions & 2 deletions packages/frontend/src/components/form/fields/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export function AutoFormSelect<T extends FieldValues>({
className,
childComponent: ChildComponent,
hideOptionalLabel,
overrideOptions,
}: {
componentProps?: AutoFormSelectProps;
} & AutoFormItemProps<T>) {
Expand All @@ -46,7 +47,9 @@ export function AutoFormSelect<T extends FieldValues>({
)._def.values;

let values: [string, string][] = [];
if (!Array.isArray(baseValues)) {
if (overrideOptions?.length) {
values = overrideOptions.map(value => [value, value]);
} else if (!Array.isArray(baseValues)) {
values = Object.entries(baseValues as object);
} else {
values = baseValues.map(value => [value, value]);
Expand Down Expand Up @@ -86,7 +89,9 @@ export function AutoFormSelect<T extends FieldValues>({
onValueChange={field.onChange}
>
<SelectTrigger {...componentProps}>
<SelectValue placeholder={componentProps?.placeholder}>
<SelectValue
placeholder={componentProps?.placeholder ?? buttonPlaceholder()}
>
{buttonPlaceholder()}
</SelectValue>
</SelectTrigger>
Expand Down
38 changes: 19 additions & 19 deletions packages/frontend/src/components/ui/select.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
'use client';

import { cn } from '@/helpers/classnames';
import * as SelectPrimitive from '@radix-ui/react-select';
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
import { ComponentProps } from 'react';

import { cn } from '../../helpers/classnames';
import { Check, ChevronDown, ChevronUp } from 'lucide-react';
import * as React from 'react';

const Select = SelectPrimitive.Root;

Expand All @@ -16,7 +15,7 @@ const SelectTrigger = ({
children,
className,
...props
}: ComponentProps<typeof SelectPrimitive.Trigger>) => (
}: React.ComponentProps<typeof SelectPrimitive.Trigger>) => (
<SelectPrimitive.Trigger
className={cn(
'border-input bg-background ring-offset-background placeholder:text-muted-foreground focus:ring-ring flex h-10 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
Expand All @@ -26,38 +25,38 @@ const SelectTrigger = ({
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDownIcon className="size-4 opacity-50" />
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
);

const SelectScrollUpButton = ({
className,
...props
}: ComponentProps<typeof SelectPrimitive.ScrollUpButton>) => (
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) => (
<SelectPrimitive.ScrollUpButton
className={cn(
'flex cursor-default items-center justify-center py-1',
className,
)}
{...props}
>
<ChevronUpIcon />
<ChevronUp className="h-4 w-4" />
</SelectPrimitive.ScrollUpButton>
);

const SelectScrollDownButton = ({
className,
...props
}: ComponentProps<typeof SelectPrimitive.ScrollDownButton>) => (
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) => (
<SelectPrimitive.ScrollDownButton
className={cn(
'flex cursor-default items-center justify-center py-1',
className,
)}
{...props}
>
<ChevronDownIcon />
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ScrollDownButton>
);

Expand All @@ -66,11 +65,11 @@ const SelectContent = ({
className,
position = 'popper',
...props
}: ComponentProps<typeof SelectPrimitive.Content>) => (
}: React.ComponentProps<typeof SelectPrimitive.Content>) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
className={cn(
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border shadow-md',
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-[--radix-popper-available-height] min-w-[8rem] overflow-hidden rounded-md border shadow-md',
position === 'popper' &&
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
className,
Expand All @@ -96,9 +95,9 @@ const SelectContent = ({
const SelectLabel = ({
className,
...props
}: ComponentProps<typeof SelectPrimitive.Label>) => (
}: React.ComponentProps<typeof SelectPrimitive.Label>) => (
<SelectPrimitive.Label
className={cn('px-2 py-1.5 text-sm font-semibold', className)}
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
{...props}
/>
);
Expand All @@ -107,27 +106,28 @@ const SelectItem = ({
children,
className,
...props
}: ComponentProps<typeof SelectPrimitive.Item>) => (
}: React.ComponentProps<typeof SelectPrimitive.Item>) => (
<SelectPrimitive.Item
className={cn(
'focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className,
)}
{...props}
>
<span className="absolute right-2 flex size-3.5 items-center justify-center">
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<CheckIcon className="size-4" />
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>

<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
);

const SelectSeparator = ({
className,
...props
}: ComponentProps<typeof SelectPrimitive.Separator>) => (
}: React.ComponentProps<typeof SelectPrimitive.Separator>) => (
<SelectPrimitive.Separator
className={cn('bg-muted -mx-1 my-1 h-px', className)}
{...props}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import gql from 'graphql-tag';
export type Admin__Core_Ai__EditMutationVariables = Types.Exact<{
provider: Types.AiProvider;
key?: Types.InputMaybe<Types.Scalars['String']['input']>;
model: Types.Scalars['String']['input'];
}>;


export type Admin__Core_Ai__EditMutation = { __typename?: 'Mutation', admin__core_ai__edit: { __typename?: 'ShowAdminCoreAiObj', provider: Types.AiProvider } };


export const Admin__Core_Ai__Edit = gql`
mutation Admin__core_ai__edit($provider: AiProvider!, $key: String) {
admin__core_ai__edit(provider: $provider, key: $key) {
mutation Admin__core_ai__edit($provider: AiProvider!, $key: String, $model: String!) {
admin__core_ai__edit(provider: $provider, key: $key, model: $model) {
provider
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
mutation Admin__core_ai__edit($provider: AiProvider!, $key: String) {
admin__core_ai__edit(provider: $provider, key: $key) {
mutation Admin__core_ai__edit(
$provider: AiProvider!
$key: String
$model: String!
) {
admin__core_ai__edit(provider: $provider, key: $key, model: $model) {
provider
}
}
Loading

0 comments on commit c92c8ef

Please sign in to comment.