diff --git a/.env.example b/.env.example deleted file mode 100644 index cd6a7d00..00000000 --- a/.env.example +++ /dev/null @@ -1,81 +0,0 @@ -# Environment -NODE_ENV=development - -# Ports -PORT=3000 - -# URLs -# These URLs must reference a publicly accessible domain or IP address, not a docker container ID (depending on your compose setup) -PUBLIC_URL=http://localhost:3000 -STORAGE_URL=http://localhost:9000/default # default is the bucket name specified in the STORAGE_BUCKET variable - -# Database (Prisma/PostgreSQL) -# This can be swapped out to use any other database, like MySQL -# Note: This is used only in the compose.yml file -POSTGRES_PORT=5432 -POSTGRES_DB=postgres -POSTGRES_USER=postgres -POSTGRES_PASSWORD=postgres - -# Database (Prisma/PostgreSQL) -DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres?schema=public - -# Authentication Secrets -# generated with `openssl rand -base64 64` -ACCESS_TOKEN_SECRET=access_token_secret -REFRESH_TOKEN_SECRET=refresh_token_secret - -# Chrome Browser (for printing) -# generated with `openssl rand -hex 32` -CHROME_PORT=8080 -CHROME_TOKEN=chrome_token -CHROME_URL=ws://localhost:8080 -# Launch puppeteer with flag to ignore https errors -# CHROME_IGNORE_HTTPS_ERRORS=true - -# Mail Server (for e-mails) -# For testing, you can use https://ethereal.email/create -MAIL_FROM=noreply@localhost -# SMTP_URL=smtp://username:password@smtp.ethereal.email:587 - -# Storage -STORAGE_ENDPOINT=localhost -STORAGE_PORT=9000 -STORAGE_REGION=us-east-1 -STORAGE_BUCKET=default -STORAGE_ACCESS_KEY=minioadmin -STORAGE_SECRET_KEY=minioadmin -STORAGE_USE_SSL=false -STORAGE_SKIP_BUCKET_CHECK=false - -# Nx Cloud (Optional) -# NX_CLOUD_ACCESS_TOKEN= - -# Crowdin (Optional) -# CROWDIN_PROJECT_ID= -# CROWDIN_PERSONAL_TOKEN= - -# Feature Flags (Optional) -# DISABLE_SIGNUPS=false -# DISABLE_EMAIL_AUTH=false - -# GitHub (OAuth, Optional) -# GITHUB_CLIENT_ID= -# GITHUB_CLIENT_SECRET= -# GITHUB_CALLBACK_URL=http://localhost:5173/api/auth/github/callback - -# Google (OAuth, Optional) -# GOOGLE_CLIENT_ID= -# GOOGLE_CLIENT_SECRET= -# GOOGLE_CALLBACK_URL=http://localhost:5173/api/auth/google/callback - -# OpenID (Optional) -# VITE_OPENID_NAME= -# OPENID_AUTHORIZATION_URL= -# OPENID_CALLBACK_URL=http://localhost:5173/api/auth/openid/callback -# OPENID_CLIENT_ID= -# OPENID_CLIENT_SECRET= -# OPENID_ISSUER= -# OPENID_SCOPE=openid profile email -# OPENID_TOKEN_URL= -# OPENID_USER_INFO_URL= diff --git a/apps/client/src/components/locale-switch.tsx b/apps/client/src/components/locale-switch.tsx index 50f1c68b..d4bdc795 100644 --- a/apps/client/src/components/locale-switch.tsx +++ b/apps/client/src/components/locale-switch.tsx @@ -1,3 +1,4 @@ +import { t } from "@lingui/macro"; import { useLingui } from "@lingui/react"; import { TranslateIcon } from "@phosphor-icons/react"; import { Button, Popover, PopoverContent, PopoverTrigger } from "@reactive-resume/ui"; @@ -13,7 +14,7 @@ export const LocaleSwitch = () => { return ( - diff --git a/apps/client/src/components/theme-switch.tsx b/apps/client/src/components/theme-switch.tsx index 37f7501b..2525cf23 100644 --- a/apps/client/src/components/theme-switch.tsx +++ b/apps/client/src/components/theme-switch.tsx @@ -1,3 +1,4 @@ +import { t } from "@lingui/macro"; import { CloudSunIcon, MoonIcon, SunIcon } from "@phosphor-icons/react"; import { useTheme } from "@reactive-resume/hooks"; import { Button } from "@reactive-resume/ui"; @@ -25,9 +26,9 @@ export const ThemeSwitch = ({ size = 20, className }: Props) => { diff --git a/apps/client/src/pages/dashboard/settings/_sections/openai.tsx b/apps/client/src/pages/dashboard/settings/_sections/openai.tsx index 434e7783..3cf92513 100644 --- a/apps/client/src/pages/dashboard/settings/_sections/openai.tsx +++ b/apps/client/src/pages/dashboard/settings/_sections/openai.tsx @@ -4,6 +4,7 @@ import { FloppyDiskIcon, TrashSimpleIcon } from "@phosphor-icons/react"; import { Alert, Button, + Checkbox, Form, FormControl, FormField, @@ -11,12 +12,15 @@ import { FormLabel, FormMessage, Input, - Checkbox, } from "@reactive-resume/ui"; import { useForm } from "react-hook-form"; import { z } from "zod"; -import { DEFAULT_MAX_TOKENS, DEFAULT_MODEL, DEFAULT_AZURE_API_VERSION } from "@/client/constants/llm"; +import { + DEFAULT_AZURE_API_VERSION, + DEFAULT_MAX_TOKENS, + DEFAULT_MODEL, +} from "@/client/constants/llm"; import { useOpenAiStore } from "@/client/stores/openai"; const formSchema = z.object({ @@ -41,12 +45,18 @@ type FormValues = z.infer; export const OpenAISettings = () => { const { - apiKey, setApiKey, - baseURL, setBaseURL, - model, setModel, - maxTokens, setMaxTokens, - isAzure, setIsAzure, - azureApiVersion, setAzureApiVersion + apiKey, + setApiKey, + baseURL, + setBaseURL, + model, + setModel, + maxTokens, + setMaxTokens, + isAzure, + setIsAzure, + azureApiVersion, + setAzureApiVersion, } = useOpenAiStore(); const isEnabled = !!apiKey; @@ -58,12 +68,19 @@ export const OpenAISettings = () => { baseURL: baseURL ?? "", model: model ?? DEFAULT_MODEL, maxTokens: maxTokens ?? DEFAULT_MAX_TOKENS, - isAzure: isAzure ?? false, + isAzure, azureApiVersion: azureApiVersion ?? DEFAULT_AZURE_API_VERSION, }, }); - const onSubmit = ({ apiKey, baseURL, model, maxTokens, isAzure, azureApiVersion }: FormValues) => { + const onSubmit = ({ + apiKey, + baseURL, + model, + maxTokens, + isAzure, + azureApiVersion, + }: FormValues) => { setApiKey(apiKey); setIsAzure(isAzure); if (baseURL) { @@ -93,7 +110,7 @@ export const OpenAISettings = () => { model: DEFAULT_MODEL, maxTokens: DEFAULT_MAX_TOKENS, isAzure: false, - azureApiVersion: DEFAULT_AZURE_API_VERSION + azureApiVersion: DEFAULT_AZURE_API_VERSION, }); }; @@ -125,10 +142,10 @@ export const OpenAISettings = () => {

- You can also integrate with Azure OpenAI by enabling the "Use Azure OpenAI" checkbox - and setting the Resource URL to your Azure OpenAI resource (e.g., - 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 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.

@@ -136,8 +153,8 @@ export const OpenAISettings = () => { 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. + http://localhost:11434/v1. You can also pick and choose models and set the + max tokens as per your preference.

@@ -163,10 +180,7 @@ export const OpenAISettings = () => { render={({ field }) => ( - {form.watch("isAzure") - ? t`Azure OpenAI Resource URL` - : t`Base URL` - } + {form.watch("isAzure") ? t`Azure OpenAI Resource URL` : t`Base URL`} { control={form.control} render={({ field }) => ( - - {form.watch("isAzure") - ? t`Deployment Name` - : t`Model` - } - + {form.watch("isAzure") ? t`Deployment Name` : t`Model`} @@ -228,7 +237,7 @@ export const OpenAISettings = () => { { field.onChange(Boolean(value)); }} diff --git a/apps/client/src/pages/home/sections/features/index.tsx b/apps/client/src/pages/home/sections/features/index.tsx index ea417dbc..5989aa4b 100644 --- a/apps/client/src/pages/home/sections/features/index.tsx +++ b/apps/client/src/pages/home/sections/features/index.tsx @@ -118,7 +118,7 @@ export const FeaturesSection = () => { whileInView={{ opacity: 1, x: 0, transition: { delay: index * 0.1 } }} > {feature.icon} -

{feature.title}

+

{feature.title}

))} diff --git a/apps/client/src/services/openai/client.ts b/apps/client/src/services/openai/client.ts index 5bbb6ef5..7e290abe 100644 --- a/apps/client/src/services/openai/client.ts +++ b/apps/client/src/services/openai/client.ts @@ -13,40 +13,25 @@ export const openai = () => { } if (isAzure) { - if (!baseURL) { - throw new Error(t`Azure OpenAI Base URL is required when using Azure OpenAI.`); + if (!baseURL || !model || !azureApiVersion) { + throw new Error( + t`Azure OpenAI Base URL, deployment name (model), and API version are required when using Azure OpenAI.`, + ); } - if (!model) { - throw new Error(t`Azure OpenAI deployment name (model) is required when using Azure OpenAI.`); - } - - if (!azureApiVersion) { - throw new Error(t`Azure OpenAI API version is required when using Azure OpenAI.`); - } - - // Construct Azure OpenAI URL: https://your-resource.openai.azure.com/openai/deployments/your-deployment - const azureBaseURL = baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL; - const constructedURL = `${azureBaseURL}/openai/deployments/${model}`; + const azureBaseURL = baseURL.replace(/\/$/, ""); return new OpenAI({ apiKey, - baseURL: constructedURL, - defaultQuery: { "api-version": azureApiVersion ?? undefined }, - dangerouslyAllowBrowser: true, - }); - } - - if (baseURL) { - return new OpenAI({ - apiKey, - baseURL, + baseURL: `${azureBaseURL}/openai/deployments/${model}`, + defaultQuery: { "api-version": azureApiVersion }, dangerouslyAllowBrowser: true, }); } return new OpenAI({ apiKey, + baseURL, dangerouslyAllowBrowser: true, }); }; diff --git a/apps/client/src/stores/openai.ts b/apps/client/src/stores/openai.ts index 0286afb2..09afdf77 100644 --- a/apps/client/src/stores/openai.ts +++ b/apps/client/src/stores/openai.ts @@ -1,7 +1,7 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; -import { DEFAULT_MAX_TOKENS, DEFAULT_MODEL, DEFAULT_AZURE_API_VERSION } from "../constants/llm"; +import { DEFAULT_AZURE_API_VERSION, DEFAULT_MAX_TOKENS, DEFAULT_MODEL } from "../constants/llm"; type OpenAIStore = { baseURL: string | null; diff --git a/apps/server/src/printer/printer.service.ts b/apps/server/src/printer/printer.service.ts index dfebf7aa..92076d7b 100644 --- a/apps/server/src/printer/printer.service.ts +++ b/apps/server/src/printer/printer.service.ts @@ -145,7 +145,7 @@ export class PrinterService { Promise.all( // eslint-disable-next-line unicorn/prefer-spread Array.from(document.images).map((img) => { - if (img.complete) return; + if (img.complete) return Promise.resolve(); return new Promise((resolve) => { // eslint-disable-next-line unicorn/prefer-add-event-listener img.onload = img.onerror = resolve; diff --git a/package.json b/package.json index bd3a124a..d91c8844 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@reactive-resume/source", "description": "A free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.", - "version": "4.4.7", + "version": "4.4.8", "license": "MIT", "private": true, "packageManager": "pnpm@10.17.1+sha512.17c560fca4867ae9473a3899ad84a88334914f379be46d455cbf92e5cf4b39d34985d452d2583baf19967fa76cb5c17bc9e245529d0b98745721aa7200ecaf7a",