import { zodResolver } from "@hookform/resolvers/zod"; import { t, Trans } from "@lingui/macro"; import { FloppyDiskIcon, TrashSimpleIcon } from "@phosphor-icons/react"; import { Alert, Button, Checkbox, Form, FormControl, FormField, FormItem, FormLabel, FormMessage, Input, } from "@reactive-resume/ui"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { DEFAULT_AZURE_API_VERSION, DEFAULT_MAX_TOKENS, DEFAULT_MODEL, } from "@/client/constants/llm"; import { useOpenAiStore } from "@/client/stores/openai"; const formSchema = z.object({ apiKey: z .string() // eslint-disable-next-line lingui/no-unlocalized-strings .min(1, "API key cannot be empty.") .default(""), baseURL: z .string() // eslint-disable-next-line lingui/no-unlocalized-strings .regex(/^https?:\/\/\S+$/, "That doesn't look like a valid URL") .or(z.literal("")) .default(""), model: z.string().default(DEFAULT_MODEL), maxTokens: z.number().default(DEFAULT_MAX_TOKENS), isAzure: z.boolean().default(false), azureApiVersion: z.string().default(DEFAULT_AZURE_API_VERSION), }); type FormValues = z.infer; export const OpenAISettings = () => { const { apiKey, setApiKey, baseURL, setBaseURL, model, setModel, maxTokens, setMaxTokens, isAzure, setIsAzure, azureApiVersion, setAzureApiVersion, } = useOpenAiStore(); const isEnabled = !!apiKey; const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { apiKey: apiKey ?? "", baseURL: baseURL ?? "", model: model ?? DEFAULT_MODEL, maxTokens: maxTokens ?? DEFAULT_MAX_TOKENS, isAzure, azureApiVersion: azureApiVersion ?? DEFAULT_AZURE_API_VERSION, }, }); const onSubmit = ({ apiKey, baseURL, model, maxTokens, isAzure, azureApiVersion, }: FormValues) => { setApiKey(apiKey); setIsAzure(isAzure); if (baseURL) { setBaseURL(baseURL); } if (model) { setModel(model); } if (maxTokens) { setMaxTokens(maxTokens); } if (azureApiVersion) { setAzureApiVersion(azureApiVersion); } }; const onRemove = () => { setApiKey(null); setBaseURL(null); setModel(DEFAULT_MODEL); setMaxTokens(DEFAULT_MAX_TOKENS); setIsAzure(false); setAzureApiVersion(DEFAULT_AZURE_API_VERSION); form.reset({ apiKey: "", baseURL: "", model: DEFAULT_MODEL, maxTokens: DEFAULT_MAX_TOKENS, isAzure: false, azureApiVersion: DEFAULT_AZURE_API_VERSION, }); }; return (

{t`OpenAI/Azure OpenAI/Ollama Integration`}

{t`You can make use of the OpenAI API, Azure OpenAI, or Ollama to help you generate content, or improve your writing while composing your resume.`}

You have the option to{" "} obtain your own OpenAI API key . This key empowers you to leverage the API as you see fit. Alternatively, if you wish to disable the AI features in Reactive Resume altogether, you can simply remove the key from your settings.

You can also integrate with Azure OpenAI by enabling the Use Azure OpenAI{" "} checkbox and setting the Resource URL to your Azure OpenAI resource:{" "} https://your-resource.openai.azure.com. Set the deployment name in the Model field and specify the appropriate API version for your Azure deployment.

You can also integrate with Ollama simply by setting the API key to sk-1234567890abcdef and the Base URL to your Ollama URL, i.e. http://localhost:11434/v1. You can also pick and choose models and set the max tokens as per your preference.

( {t`OpenAI/Ollama API Key`} )} /> ( {form.watch("isAzure") ? t`Azure OpenAI Resource URL` : t`Base URL`} )} /> ( {form.watch("isAzure") ? t`Deployment Name` : t`Model`} )} /> ( {t`Max Tokens`} { field.onChange(e.target.valueAsNumber); }} /> )} /> ( { field.onChange(Boolean(value)); }} />
{t`Use Azure OpenAI`}
)} /> ( {t`Azure API Version`} )} />
{isEnabled && ( )}

Your API key is securely stored in the browser's local storage and is only utilized when making requests to OpenAI via their official SDK. Rest assured that your key is not transmitted to any external server except when interacting with OpenAI's services.

Note: By utilizing the OpenAI API, you acknowledge and accept the{" "} terms of use {" "} and{" "} privacy policy {" "} outlined by OpenAI. Please note that Reactive Resume bears no responsibility for any improper or unauthorized utilization of the service, and any resulting repercussions or liabilities solely rest on the user.
); };