mirror of
https://github.com/marcogll/TaxHacker_s23.git
synced 2026-01-13 13:25:18 +00:00
feat: more llm provider options (google, mistral) (#28)
* feat: add google provider * fix: default for google model * feat: multiple providers * fix: defaults from env for login form * fix: add mistral to env files * chore: delete unused code * chore: revert database url to original * fix: render default value for api key from env on server * fix: type errors during compilation --------- Co-authored-by: Vasily Zubarev <me@vas3k.ru>
This commit is contained in:
@@ -9,6 +9,12 @@ DATABASE_URL="postgresql://user@localhost:5432/taxhacker"
|
||||
OPENAI_MODEL_NAME="gpt-4o-mini"
|
||||
OPENAI_API_KEY="" # "sk-..."
|
||||
|
||||
GOOGLE_MODEL_NAME="gemini-2.5-flash"
|
||||
GOOGLE_API_KEY=""
|
||||
|
||||
MISTRAL_MODEL_NAME="mistral-medium-latest"
|
||||
MISTRAL_API_KEY=""
|
||||
|
||||
# Auth Config
|
||||
BETTER_AUTH_SECRET="random-secret-key" # please use any long random string here
|
||||
|
||||
|
||||
@@ -152,8 +152,12 @@ Configure TaxHacker to suit your needs with these environment variables:
|
||||
| `SELF_HOSTED_MODE` | No | Set it to "true" if you're self-hosting the app: it enables auto-login, custom API keys, and more | `true` |
|
||||
| `DISABLE_SIGNUP` | No | Disable new user registration on your instance | `false` |
|
||||
| `BETTER_AUTH_SECRET` | Yes | Secret key for authentication (min 16 characters) | `random-secret-key` |
|
||||
| `OPENAI_MODEL_NAME` | No | OpenAI model to use for AI features | `gpt-4o-mini` |
|
||||
| `OPENAI_API_KEY` | No | OpenAI API key for AI features. In self-hosted mode you can set it up in settings too. | `sk-...` |
|
||||
|
||||
You can also specify LLM provider options in settings or with environment variables:
|
||||
|
||||
- For OpenAI: `OPENAI_MODEL_NAME` and `OPENAI_API_KEY`
|
||||
- For Google: `GOOGLE_MODEL_NAME` and `GOOGLE_API_KEY`
|
||||
- For Mistral: `MISTRAL_MODEL_NAME` and `MISTRAL_API_KEY`
|
||||
|
||||
|
||||
## ⌨️ Local Development
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"use server"
|
||||
|
||||
import { ActionState } from "@/lib/actions"
|
||||
import config from "@/lib/config"
|
||||
import OpenAI from "openai"
|
||||
import { AnalyzeAttachment } from "./attachments"
|
||||
import { updateFile } from "@/models/files"
|
||||
import { getSettings, getLLMSettings } from "@/models/settings"
|
||||
import { requestLLM } from "./providers/llmProvider"
|
||||
|
||||
export type AnalysisResult = {
|
||||
output: Record<string, string>
|
||||
@@ -15,52 +15,39 @@ export async function analyzeTransaction(
|
||||
prompt: string,
|
||||
schema: Record<string, unknown>,
|
||||
attachments: AnalyzeAttachment[],
|
||||
apiKey: string,
|
||||
fileId: string,
|
||||
userId: string
|
||||
): Promise<ActionState<AnalysisResult>> {
|
||||
const openai = new OpenAI({
|
||||
apiKey,
|
||||
})
|
||||
console.log("RUNNING AI ANALYSIS")
|
||||
console.log("PROMPT:", prompt)
|
||||
console.log("SCHEMA:", schema)
|
||||
|
||||
const settings = await getSettings(userId)
|
||||
const llmSettings = getLLMSettings(settings)
|
||||
|
||||
try {
|
||||
const response = await openai.responses.create({
|
||||
model: config.ai.modelName,
|
||||
input: [
|
||||
{
|
||||
role: "user",
|
||||
content: prompt,
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: attachments.map((attachment) => ({
|
||||
type: "input_image",
|
||||
detail: "auto",
|
||||
image_url: `data:${attachment.contentType};base64,${attachment.base64}`,
|
||||
})),
|
||||
},
|
||||
],
|
||||
text: {
|
||||
format: {
|
||||
type: "json_schema",
|
||||
name: "transaction",
|
||||
schema: schema,
|
||||
strict: true,
|
||||
},
|
||||
},
|
||||
const response = await requestLLM(llmSettings, {
|
||||
prompt,
|
||||
schema,
|
||||
attachments,
|
||||
})
|
||||
|
||||
console.log("ChatGPT response:", response.output_text)
|
||||
console.log("ChatGPT tokens used:", response.usage)
|
||||
if (response.error) {
|
||||
throw new Error(response.error)
|
||||
}
|
||||
|
||||
const result = response.output
|
||||
const tokensUsed = response.tokensUsed || 0
|
||||
|
||||
console.log("LLM response:", result)
|
||||
console.log("LLM tokens used:", tokensUsed)
|
||||
|
||||
const result = JSON.parse(response.output_text)
|
||||
|
||||
await updateFile(fileId, userId, { cachedParseResult: result })
|
||||
|
||||
return { success: true, data: { output: result, tokensUsed: response.usage?.total_tokens || 0 } }
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
output: result,
|
||||
tokensUsed: tokensUsed
|
||||
},
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("AI Analysis error:", error)
|
||||
return {
|
||||
|
||||
115
ai/providers/llmProvider.ts
Normal file
115
ai/providers/llmProvider.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { ChatOpenAI } from "@langchain/openai"
|
||||
import { ChatGoogleGenerativeAI } from "@langchain/google-genai"
|
||||
import { ChatMistralAI } from "@langchain/mistralai"
|
||||
import { BaseMessage, HumanMessage } from "@langchain/core/messages"
|
||||
|
||||
export type LLMProvider = "openai" | "google" | "mistral"
|
||||
|
||||
export interface LLMConfig {
|
||||
provider: LLMProvider
|
||||
apiKey: string
|
||||
model: string
|
||||
}
|
||||
|
||||
export interface LLMSettings {
|
||||
providers: LLMConfig[]
|
||||
}
|
||||
|
||||
export interface LLMRequest {
|
||||
prompt: string
|
||||
schema?: Record<string, unknown>
|
||||
attachments?: any[]
|
||||
}
|
||||
|
||||
export interface LLMResponse {
|
||||
output: Record<string, string>
|
||||
tokensUsed?: number
|
||||
provider: LLMProvider
|
||||
error?: string
|
||||
}
|
||||
|
||||
async function requestLLMUnified(config: LLMConfig, req: LLMRequest): Promise<LLMResponse> {
|
||||
try {
|
||||
const temperature = 0;
|
||||
let model: any;
|
||||
if (config.provider === "openai") {
|
||||
model = new ChatOpenAI({
|
||||
apiKey: config.apiKey,
|
||||
model: config.model,
|
||||
temperature: temperature,
|
||||
});
|
||||
} else if (config.provider === "google") {
|
||||
model = new ChatGoogleGenerativeAI({
|
||||
apiKey: config.apiKey,
|
||||
model: config.model,
|
||||
temperature: temperature,
|
||||
});
|
||||
} else if (config.provider === "mistral") {
|
||||
model = new ChatMistralAI({
|
||||
apiKey: config.apiKey,
|
||||
model: config.model,
|
||||
temperature: temperature,
|
||||
});
|
||||
} else {
|
||||
return {
|
||||
output: {},
|
||||
provider: config.provider,
|
||||
error: "Unknown provider",
|
||||
};
|
||||
}
|
||||
|
||||
const structuredModel = model.withStructuredOutput(req.schema, { 'name': 'transaction'});
|
||||
|
||||
let message_content: any = [{ type: "text", text: req.prompt }];
|
||||
if (req.attachments && req.attachments.length > 0) {
|
||||
const images = req.attachments.map(att => ({
|
||||
type: "image_url",
|
||||
image_url: {
|
||||
url: `data:${att.contentType};base64,${att.base64}`
|
||||
},
|
||||
}));
|
||||
message_content.push(...images);
|
||||
}
|
||||
const messages: BaseMessage[] = [
|
||||
new HumanMessage({ content: message_content })
|
||||
];
|
||||
|
||||
const response = await structuredModel.invoke(messages);
|
||||
|
||||
return {
|
||||
output: response,
|
||||
provider: config.provider,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
output: {},
|
||||
provider: config.provider,
|
||||
error: error instanceof Error ? error.message : `${config.provider} request failed`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function requestLLM(settings: LLMSettings, req: LLMRequest): Promise<LLMResponse> {
|
||||
for (const config of settings.providers) {
|
||||
if (!config.apiKey || !config.model) {
|
||||
console.info('Skipping provider:', config.provider);
|
||||
continue;
|
||||
}
|
||||
console.info('Use provider:', config.provider);
|
||||
|
||||
const response = await requestLLMUnified(config, req);
|
||||
|
||||
if (!response.error) {
|
||||
return response;
|
||||
}
|
||||
else {
|
||||
console.error(response.error)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
output: {},
|
||||
provider: settings.providers[0]?.provider || "openai",
|
||||
error: "All LLM providers failed or are not configured",
|
||||
};
|
||||
}
|
||||
@@ -31,20 +31,15 @@ export async function analyzeFileAction(
|
||||
const user = await getCurrentUser()
|
||||
|
||||
if (!file || file.userId !== user.id) {
|
||||
return { success: false, error: "File not found or does not belong to the user" }
|
||||
}
|
||||
|
||||
const apiKey = settings.openai_api_key || config.ai.openaiApiKey || ""
|
||||
if (!apiKey) {
|
||||
return { success: false, error: "OpenAI API key is not set" }
|
||||
}
|
||||
|
||||
if (isAiBalanceExhausted(user)) {
|
||||
return {
|
||||
success: false,
|
||||
error: "You used all of your pre-paid AI scans, please upgrade your account or buy new subscription plan",
|
||||
return { success: false, error: "File not found or does not belong to the user" }
|
||||
}
|
||||
|
||||
if (isAiBalanceExhausted(user)) {
|
||||
return {
|
||||
success: false,
|
||||
error: "You used all of your pre-paid AI scans, please upgrade your account or buy new subscription plan",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isSubscriptionExpired(user)) {
|
||||
return {
|
||||
@@ -70,7 +65,7 @@ export async function analyzeFileAction(
|
||||
|
||||
const schema = fieldsToJsonSchema(fields)
|
||||
|
||||
const results = await analyzeTransaction(prompt, schema, attachments, apiKey, file.id, user.id)
|
||||
const results = await analyzeTransaction(prompt, schema, attachments, file.id, user.id)
|
||||
|
||||
console.log("Analysis results:", results)
|
||||
|
||||
@@ -98,7 +93,7 @@ export async function saveFileAsTransactionAction(
|
||||
const file = await getFileById(fileId, user.id)
|
||||
if (!file) throw new Error("File not found")
|
||||
|
||||
// Create transaction
|
||||
// Create transaction
|
||||
const transaction = await createTransaction(user.id, validatedForm.data)
|
||||
|
||||
// Move file to processed location
|
||||
|
||||
@@ -38,14 +38,14 @@ export default async function UnsortedPage() {
|
||||
{files.length > 1 && <AnalyzeAllButton />}
|
||||
</header>
|
||||
|
||||
{config.selfHosted.isEnabled && !settings.openai_api_key && (
|
||||
{config.selfHosted.isEnabled && !settings.openai_api_key && !settings.google_api_key && !settings.mistral_api_key && (
|
||||
<Alert>
|
||||
<Settings className="h-4 w-4 mt-2" />
|
||||
<div className="flex flex-row justify-between pt-2">
|
||||
<div className="flex flex-col">
|
||||
<AlertTitle>ChatGPT API Key is required for analyzing files</AlertTitle>
|
||||
<AlertTitle>LLM provider API Key is required for analyzing files</AlertTitle>
|
||||
<AlertDescription>
|
||||
Please set your OpenAI API key in the settings to use the analyze form.
|
||||
Please set your LLM provider API key in the settings to use the analyze form.
|
||||
</AlertDescription>
|
||||
</div>
|
||||
<Link href="/settings/llm">
|
||||
|
||||
@@ -13,11 +13,20 @@ export async function selfHostedGetStartedAction(formData: FormData) {
|
||||
await createUserDefaults(user.id)
|
||||
}
|
||||
|
||||
const openaiApiKey = formData.get("openai_api_key")
|
||||
if (openaiApiKey) {
|
||||
await updateSettings(user.id, "openai_api_key", openaiApiKey as string)
|
||||
const apiKeys = [
|
||||
"openai_api_key",
|
||||
"google_api_key",
|
||||
"mistral_api_key"
|
||||
]
|
||||
|
||||
for (const key of apiKeys) {
|
||||
const value = formData.get(key)
|
||||
if (value) {
|
||||
await updateSettings(user.id, key, value as string)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const defaultCurrency = formData.get("default_currency")
|
||||
if (defaultCurrency) {
|
||||
await updateSettings(user.id, "default_currency", defaultCurrency as string)
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { FormSelectCurrency } from "@/components/forms/select-currency"
|
||||
import { FormInput } from "@/components/forms/simple"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardDescription, CardTitle } from "@/components/ui/card"
|
||||
import { ColoredText } from "@/components/ui/colored-text"
|
||||
import config from "@/lib/config"
|
||||
import { DEFAULT_CURRENCIES, DEFAULT_SETTINGS } from "@/models/defaults"
|
||||
import { getSelfHostedUser } from "@/models/users"
|
||||
import { ShieldAlert } from "lucide-react"
|
||||
import Image from "next/image"
|
||||
import { redirect } from "next/navigation"
|
||||
import { selfHostedGetStartedAction } from "../actions"
|
||||
import { PROVIDERS } from "@/lib/llm-providers"
|
||||
import SelfHostedSetupFormClient from "./setup-form-client"
|
||||
|
||||
export default async function SelfHostedWelcomePage() {
|
||||
if (!config.selfHosted.isEnabled) {
|
||||
@@ -35,6 +32,14 @@ export default async function SelfHostedWelcomePage() {
|
||||
redirect(config.selfHosted.redirectUrl)
|
||||
}
|
||||
|
||||
// Собираем дефолтные ключи для всех провайдеров
|
||||
const defaultProvider = PROVIDERS[0].key
|
||||
const defaultApiKeys: Record<string, string> = {
|
||||
openai: config.ai.openaiApiKey ?? "",
|
||||
google: config.ai.googleApiKey ?? "",
|
||||
mistral: config.ai.mistralApiKey ?? "",
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="w-full max-w-xl mx-auto p-8 flex flex-col items-center justify-center gap-4">
|
||||
<Image src="/logo/512.png" alt="Logo" width={144} height={144} className="w-36 h-36" />
|
||||
@@ -43,36 +48,7 @@ export default async function SelfHostedWelcomePage() {
|
||||
</CardTitle>
|
||||
<CardDescription className="flex flex-col gap-4 text-center text-lg">
|
||||
<p>Welcome to your own instance of TaxHacker. Let's set up a couple of settings to get started.</p>
|
||||
|
||||
<form action={selfHostedGetStartedAction} className="flex flex-col gap-8 pt-8">
|
||||
<div>
|
||||
<FormInput title="OpenAI API Key" name="openai_api_key" defaultValue={config.ai.openaiApiKey} />
|
||||
|
||||
<small className="text-xs text-muted-foreground">
|
||||
Get your API key from{" "}
|
||||
<a
|
||||
href="https://platform.openai.com/settings/organization/api-keys"
|
||||
target="_blank"
|
||||
className="underline"
|
||||
>
|
||||
OpenAI Platform Console
|
||||
</a>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center justify-center gap-2">
|
||||
<FormSelectCurrency
|
||||
title="Default Currency"
|
||||
name="default_currency"
|
||||
defaultValue={DEFAULT_SETTINGS.find((s) => s.code === "default_currency")?.value ?? "EUR"}
|
||||
currencies={DEFAULT_CURRENCIES}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button type="submit" className="w-auto p-6">
|
||||
Get Started
|
||||
</Button>
|
||||
</form>
|
||||
<SelfHostedSetupFormClient defaultProvider={defaultProvider} defaultApiKeys={defaultApiKeys} />
|
||||
</CardDescription>
|
||||
</Card>
|
||||
)
|
||||
|
||||
76
app/(auth)/self-hosted/setup-form-client.tsx
Normal file
76
app/(auth)/self-hosted/setup-form-client.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
"use client"
|
||||
import { useState, useRef, useEffect, useCallback } from "react"
|
||||
import { FormSelectCurrency } from "@/components/forms/select-currency"
|
||||
import { FormInput } from "@/components/forms/simple"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { DEFAULT_CURRENCIES, DEFAULT_SETTINGS } from "@/models/defaults"
|
||||
import { selfHostedGetStartedAction } from "../actions"
|
||||
import { FormSelect } from "@/components/forms/simple"
|
||||
import { PROVIDERS } from "@/lib/llm-providers"
|
||||
|
||||
type Props = {
|
||||
defaultProvider: string
|
||||
defaultApiKeys: Record<string, string>
|
||||
}
|
||||
|
||||
export default function SelfHostedSetupFormClient({ defaultProvider, defaultApiKeys }: Props) {
|
||||
const [provider, setProvider] = useState(defaultProvider)
|
||||
const selected = PROVIDERS.find(p => p.key === provider)!
|
||||
const getDefaultApiKey = useCallback((providerKey: string) => defaultApiKeys[providerKey] ?? "", [defaultApiKeys])
|
||||
|
||||
const [apiKey, setApiKey] = useState(getDefaultApiKey(provider))
|
||||
const userTyped = useRef(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!userTyped.current) {
|
||||
setApiKey(getDefaultApiKey(provider))
|
||||
}
|
||||
userTyped.current = false
|
||||
}, [provider, getDefaultApiKey])
|
||||
|
||||
return (
|
||||
<form action={selfHostedGetStartedAction} className="flex flex-col gap-8 pt-8">
|
||||
<div className="flex flex-row gap-4 items-center justify-center">
|
||||
<FormSelect
|
||||
title="LLM provider"
|
||||
name="provider"
|
||||
value={provider}
|
||||
onValueChange={setProvider}
|
||||
items={PROVIDERS.map(p => ({
|
||||
code: p.key,
|
||||
name: p.label,
|
||||
logo: p.logo
|
||||
}))}
|
||||
/>
|
||||
<FormSelectCurrency
|
||||
title="Default Currency"
|
||||
name="default_currency"
|
||||
defaultValue={DEFAULT_SETTINGS.find((s) => s.code === "default_currency")?.value ?? "EUR"}
|
||||
currencies={DEFAULT_CURRENCIES}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<FormInput
|
||||
title={`${selected.label} API Key`}
|
||||
name={selected.apiKeyName}
|
||||
value={apiKey ?? ""}
|
||||
onChange={e => {
|
||||
setApiKey(e.target.value)
|
||||
userTyped.current = true
|
||||
}}
|
||||
placeholder={selected.placeholder}
|
||||
/>
|
||||
<small className="text-xs text-muted-foreground flex justify-center mt-2">
|
||||
Get key from
|
||||
{"\u00A0"}
|
||||
<a href={selected.help.url} target="_blank" className="underline">
|
||||
{selected.help.label}
|
||||
</a>
|
||||
</small>
|
||||
</div>
|
||||
<Button type="submit" className="w-auto p-6">
|
||||
Get Started
|
||||
</Button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
"use client"
|
||||
import Image from "next/image"
|
||||
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
@@ -87,9 +88,10 @@ export const FormSelect = ({
|
||||
placeholder,
|
||||
hideIfEmpty = false,
|
||||
isRequired = false,
|
||||
onValueChange,
|
||||
...props
|
||||
}: {
|
||||
items: Array<{ code: string; name: string; color?: string; badge?: string }>
|
||||
items: Array<{ code: string; name: string; color?: string; badge?: string; logo?: string }>
|
||||
title?: string
|
||||
emptyValue?: string
|
||||
placeholder?: string
|
||||
@@ -105,7 +107,11 @@ export const FormSelect = ({
|
||||
return (
|
||||
<span className="flex flex-col gap-1">
|
||||
{title && <span className="text-sm font-medium">{title}</span>}
|
||||
<Select {...props}>
|
||||
<Select
|
||||
value={props.value}
|
||||
onValueChange={onValueChange}
|
||||
{...props}
|
||||
>
|
||||
<SelectTrigger className={cn("w-full min-w-[150px] bg-background", isRequired && isEmpty && "bg-yellow-50")}>
|
||||
<SelectValue placeholder={placeholder} />
|
||||
</SelectTrigger>
|
||||
@@ -114,6 +120,9 @@ export const FormSelect = ({
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.code} value={item.code}>
|
||||
<div className="flex items-center gap-2 text-base pr-2">
|
||||
{item.logo && (
|
||||
<Image src={item.logo} alt={item.name} width={20} height={20} className="rounded-full" />
|
||||
)}
|
||||
{item.badge && <Badge className="px-2">{item.badge}</Badge>}
|
||||
{!item.badge && item.color && (
|
||||
<div className="w-2 h-2 rounded-full" style={{ backgroundColor: item.color }} />
|
||||
|
||||
@@ -3,44 +3,91 @@
|
||||
import { fieldsToJsonSchema } from "@/ai/schema"
|
||||
import { saveSettingsAction } from "@/app/(app)/settings/actions"
|
||||
import { FormError } from "@/components/forms/error"
|
||||
import { FormInput, FormTextarea } from "@/components/forms/simple"
|
||||
import { FormTextarea } from "@/components/forms/simple"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardTitle } from "@/components/ui/card"
|
||||
import { Field } from "@/prisma/client"
|
||||
import { CircleCheckBig, Edit } from "lucide-react"
|
||||
import { CircleCheckBig, Edit, GripVertical } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { useActionState } from "react"
|
||||
import { useState, useActionState } from "react"
|
||||
import {
|
||||
DndContext,
|
||||
closestCenter,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors
|
||||
} from "@dnd-kit/core"
|
||||
import type { DragEndEvent } from "@dnd-kit/core";
|
||||
import {
|
||||
arrayMove,
|
||||
SortableContext,
|
||||
useSortable,
|
||||
verticalListSortingStrategy
|
||||
} from "@dnd-kit/sortable"
|
||||
import { PROVIDERS } from "@/lib/llm-providers";
|
||||
|
||||
|
||||
function getInitialProviderOrder(settings: Record<string, string>) {
|
||||
let order: string[] = []
|
||||
if (!settings.llm_providers) {
|
||||
order = ['openai', 'google', 'mistral']
|
||||
} else {
|
||||
order = settings.llm_providers.split(",").map(p => p.trim())
|
||||
}
|
||||
// Remove duplicates and keep only valid providers
|
||||
return order.filter((key, idx) => PROVIDERS.some(p => p.key === key) && order.indexOf(key) === idx)
|
||||
}
|
||||
|
||||
export default function LLMSettingsForm({
|
||||
settings,
|
||||
fields,
|
||||
showApiKey = true,
|
||||
}: {
|
||||
settings: Record<string, string>
|
||||
fields: Field[]
|
||||
showApiKey?: boolean
|
||||
}) {
|
||||
const [saveState, saveAction, pending] = useActionState(saveSettingsAction, null)
|
||||
const [providerOrder, setProviderOrder] = useState<string[]>(getInitialProviderOrder(settings))
|
||||
|
||||
// Controlled values for each provider
|
||||
const [providerValues, setProviderValues] = useState(() => {
|
||||
const values: Record<string, { apiKey: string; model: string }> = {}
|
||||
PROVIDERS.forEach((provider) => {
|
||||
values[provider.key] = {
|
||||
apiKey: settings[provider.apiKeyName],
|
||||
model: settings[provider.modelName] || provider.defaultModelName,
|
||||
}
|
||||
})
|
||||
return values
|
||||
})
|
||||
|
||||
function handleProviderValueChange(providerKey: string, field: "apiKey" | "model", value: string) {
|
||||
setProviderValues((prev) => ({
|
||||
...prev,
|
||||
[providerKey]: {
|
||||
...prev[providerKey],
|
||||
[field]: value,
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<form action={saveAction} className="space-y-4">
|
||||
{showApiKey && (
|
||||
<>
|
||||
<FormInput title="OpenAI API Key" name="openai_api_key" defaultValue={settings.openai_api_key} />
|
||||
|
||||
<small className="text-muted-foreground">
|
||||
Get your API key from{" "}
|
||||
<a
|
||||
href="https://platform.openai.com/settings/organization/api-keys"
|
||||
target="_blank"
|
||||
className="underline"
|
||||
>
|
||||
OpenAI Platform Console
|
||||
</a>
|
||||
</small>
|
||||
</>
|
||||
)}
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">LLM providers</label>
|
||||
<DndProviderBlocks
|
||||
providerOrder={providerOrder}
|
||||
setProviderOrder={setProviderOrder}
|
||||
providerValues={providerValues}
|
||||
handleProviderValueChange={handleProviderValueChange}
|
||||
/>
|
||||
<small className="text-muted-foreground">
|
||||
Drag provider blocks to reorder. First is highest priority.
|
||||
</small>
|
||||
</div>
|
||||
<input type="hidden" name="llm_providers" value={providerOrder.join(",")} />
|
||||
|
||||
<FormTextarea
|
||||
title="Prompt for File Analysis Form"
|
||||
@@ -90,3 +137,106 @@ export default function LLMSettingsForm({
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
type DndProviderBlocksProps = {
|
||||
providerOrder: string[];
|
||||
setProviderOrder: React.Dispatch<React.SetStateAction<string[]>>;
|
||||
providerValues: Record<string, { apiKey: string; model: string }>;
|
||||
handleProviderValueChange: (providerKey: string, field: "apiKey" | "model", value: string) => void;
|
||||
};
|
||||
|
||||
function DndProviderBlocks({ providerOrder, setProviderOrder, providerValues, handleProviderValueChange }: DndProviderBlocksProps) {
|
||||
const sensors = useSensors(useSensor(PointerSensor))
|
||||
function handleDragEnd(event: DragEndEvent) {
|
||||
const { active, over } = event
|
||||
if (!over || active.id === over.id) return
|
||||
const oldIndex = providerOrder.indexOf(active.id as string)
|
||||
const newIndex = providerOrder.indexOf(over.id as string)
|
||||
setProviderOrder(arrayMove(providerOrder, oldIndex, newIndex))
|
||||
}
|
||||
return (
|
||||
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
||||
<SortableContext items={providerOrder} strategy={verticalListSortingStrategy}>
|
||||
{providerOrder.map((providerKey, idx) => (
|
||||
<SortableProviderBlock
|
||||
key={providerKey}
|
||||
id={providerKey}
|
||||
idx={idx}
|
||||
providerKey={providerKey}
|
||||
value={providerValues[providerKey]}
|
||||
handleValueChange={handleProviderValueChange}
|
||||
/>
|
||||
))}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
)
|
||||
}
|
||||
|
||||
type SortableProviderBlockProps = {
|
||||
id: string;
|
||||
idx: number;
|
||||
providerKey: string;
|
||||
value: { apiKey: string; model: string };
|
||||
handleValueChange: (providerKey: string, field: "apiKey" | "model", value: string) => void;
|
||||
};
|
||||
|
||||
function SortableProviderBlock({ id, idx, providerKey, value, handleValueChange }: SortableProviderBlockProps) {
|
||||
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id })
|
||||
|
||||
const provider = PROVIDERS.find(p => p.key === providerKey)
|
||||
if (!provider) return null
|
||||
return (
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
style={{
|
||||
transform: transform ? `translateY(${transform.y}px)` : undefined,
|
||||
transition,
|
||||
opacity: isDragging ? 0.6 : 1,
|
||||
}}
|
||||
className={`bg-muted rounded-lg p-4 shadow flex flex-col gap-2 mb-2`}
|
||||
>
|
||||
<div className="flex flex-row items-center gap-2 mb-2">
|
||||
{/* Drag handle */}
|
||||
<span
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
className="cursor-grab p-1 rounded hover:bg-accent transition inline-flex items-center"
|
||||
aria-label="Drag to reorder"
|
||||
>
|
||||
<GripVertical className="w-5 h-5 text-muted-foreground" />
|
||||
</span>
|
||||
<span className="font-semibold">{provider.label}</span>
|
||||
</div>
|
||||
<div className="flex flex-row gap-4 items-center">
|
||||
<input
|
||||
type="text"
|
||||
name={provider.apiKeyName}
|
||||
value={value.apiKey}
|
||||
onChange={e => handleValueChange(provider.key, "apiKey", e.target.value)}
|
||||
className="flex-1 border rounded px-2 py-1"
|
||||
placeholder="API key"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name={provider.modelName}
|
||||
value={value.model}
|
||||
onChange={e => handleValueChange(provider.key, "model", e.target.value)}
|
||||
className="flex-1 border rounded px-2 py-1"
|
||||
placeholder="Model name"
|
||||
/>
|
||||
</div>
|
||||
{provider.apiDoc && (
|
||||
<small className="text-muted-foreground">
|
||||
Get your API key from{" "}
|
||||
<a
|
||||
href={provider.apiDoc}
|
||||
target="_blank"
|
||||
className="underline"
|
||||
>
|
||||
{provider.apiDocLabel}
|
||||
</a>
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ services:
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
container_name: taxhacker-postgres
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
|
||||
@@ -7,6 +7,12 @@ export const settingsFormSchema = z.object({
|
||||
default_category: z.string().optional(),
|
||||
default_project: z.string().optional(),
|
||||
openai_api_key: z.string().optional(),
|
||||
openai_model_name: z.string().default('gpt-4o-mini'),
|
||||
google_api_key: z.string().optional(),
|
||||
google_model_name: z.string().default("gemini-2.5-flash"),
|
||||
mistral_api_key: z.string().optional(),
|
||||
mistral_model_name: z.string().default("mistral-medium-latest"),
|
||||
llm_providers: z.string().default('openai,google,mistral'),
|
||||
prompt_analyse_new_file: z.string().optional(),
|
||||
is_welcome_message_hidden: z.string().optional(),
|
||||
})
|
||||
|
||||
@@ -6,6 +6,10 @@ const envSchema = z.object({
|
||||
SELF_HOSTED_MODE: z.enum(["true", "false"]).default("true"),
|
||||
OPENAI_API_KEY: z.string().optional(),
|
||||
OPENAI_MODEL_NAME: z.string().default("gpt-4o-mini"),
|
||||
GOOGLE_API_KEY: z.string().optional(),
|
||||
GOOGLE_MODEL_NAME: z.string().default("gemini-2.5-flash"),
|
||||
MISTRAL_API_KEY: z.string().optional(),
|
||||
MISTRAL_MODEL_NAME: z.string().default("mistral-medium-latest"),
|
||||
BETTER_AUTH_SECRET: z
|
||||
.string()
|
||||
.min(16, "Auth secret must be at least 16 characters")
|
||||
@@ -50,7 +54,11 @@ const config = {
|
||||
},
|
||||
ai: {
|
||||
openaiApiKey: env.OPENAI_API_KEY,
|
||||
modelName: env.OPENAI_MODEL_NAME,
|
||||
openaiModelName: env.OPENAI_MODEL_NAME,
|
||||
googleApiKey: env.GOOGLE_API_KEY,
|
||||
googleModelName: env.GOOGLE_MODEL_NAME,
|
||||
mistralApiKey: env.MISTRAL_API_KEY,
|
||||
mistralModelName: env.MISTRAL_MODEL_NAME,
|
||||
},
|
||||
auth: {
|
||||
secret: env.BETTER_AUTH_SECRET,
|
||||
|
||||
47
lib/llm-providers.ts
Normal file
47
lib/llm-providers.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
export const PROVIDERS = [
|
||||
{
|
||||
key: "openai",
|
||||
label: "OpenAI",
|
||||
apiKeyName: "openai_api_key",
|
||||
modelName: "openai_model_name",
|
||||
defaultModelName: "gpt-4o-mini",
|
||||
apiDoc: "https://platform.openai.com/settings/organization/api-keys",
|
||||
apiDocLabel: "OpenAI Platform Console",
|
||||
placeholder: "sk-...",
|
||||
help: {
|
||||
url: "https://platform.openai.com/settings/organization/api-keys",
|
||||
label: "OpenAI Platform Console"
|
||||
},
|
||||
logo: "/logo/openai.svg"
|
||||
},
|
||||
{
|
||||
key: "google",
|
||||
label: "Google",
|
||||
apiKeyName: "google_api_key",
|
||||
modelName: "google_model_name",
|
||||
defaultModelName: "gemini-2.5-flash",
|
||||
apiDoc: "https://aistudio.google.com/apikey",
|
||||
apiDocLabel: "Google AI Studio",
|
||||
placeholder: "...",
|
||||
help: {
|
||||
url: "https://aistudio.google.com/apikey",
|
||||
label: "Google AI Studio"
|
||||
},
|
||||
logo: "/logo/google.svg"
|
||||
},
|
||||
{
|
||||
key: "mistral",
|
||||
label: "Mistral",
|
||||
apiKeyName: "mistral_api_key",
|
||||
modelName: "mistral_model_name",
|
||||
defaultModelName: "mistral-medium-latest",
|
||||
apiDoc: "https://admin.mistral.ai/organization/api-keys",
|
||||
apiDocLabel: "Mistral Admin Console",
|
||||
placeholder: "...",
|
||||
help: {
|
||||
url: "https://admin.mistral.ai/organization/api-keys",
|
||||
label: "Mistral Admin Console"
|
||||
},
|
||||
logo: "/logo/mistral.svg"
|
||||
},
|
||||
]
|
||||
@@ -1,12 +1,51 @@
|
||||
import { prisma } from "@/lib/db"
|
||||
import { PROVIDERS } from "@/lib/llm-providers"
|
||||
import { cache } from "react"
|
||||
import { LLMProvider } from "@/ai/providers/llmProvider"
|
||||
|
||||
export type SettingsMap = Record<string, string>
|
||||
|
||||
/**
|
||||
* Helper to extract LLM provider settings from SettingsMap.
|
||||
*/
|
||||
export function getLLMSettings(settings: SettingsMap) {
|
||||
const priorities = (settings.llm_providers || "openai,google,mistral").split(",").map(p => p.trim()).filter(Boolean)
|
||||
|
||||
const providers = priorities.map((provider) => {
|
||||
if (provider === "openai") {
|
||||
return {
|
||||
provider: provider as LLMProvider,
|
||||
apiKey: settings.openai_api_key || "",
|
||||
model: settings.openai_model_name || PROVIDERS[0]['defaultModelName'],
|
||||
}
|
||||
}
|
||||
if (provider === "google") {
|
||||
return {
|
||||
provider: provider as LLMProvider,
|
||||
apiKey: settings.google_api_key || "",
|
||||
model: settings.google_model_name || PROVIDERS[1]['defaultModelName'],
|
||||
}
|
||||
}
|
||||
if (provider === "mistral") {
|
||||
return {
|
||||
provider: provider as LLMProvider,
|
||||
apiKey: settings.mistral_api_key || "",
|
||||
model: settings.mistral_model_name || PROVIDERS[2]['defaultModelName'],
|
||||
}
|
||||
}
|
||||
return null
|
||||
}).filter((provider): provider is NonNullable<typeof provider> => provider !== null)
|
||||
|
||||
return {
|
||||
providers,
|
||||
}
|
||||
}
|
||||
|
||||
export const getSettings = cache(async (userId: string): Promise<SettingsMap> => {
|
||||
const settings = await prisma.setting.findMany({
|
||||
where: { userId },
|
||||
})
|
||||
|
||||
return settings.reduce((acc, setting) => {
|
||||
acc[setting.code] = setting.value || ""
|
||||
return acc
|
||||
|
||||
661
package-lock.json
generated
661
package-lock.json
generated
@@ -8,8 +8,13 @@
|
||||
"name": "taxhacker",
|
||||
"version": "0.5.5",
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@fast-csv/format": "^5.0.2",
|
||||
"@fast-csv/parse": "^5.0.2",
|
||||
"@langchain/google-genai": "^0.2.14",
|
||||
"@langchain/mistralai": "^0.2.1",
|
||||
"@langchain/openai": "^0.6.1",
|
||||
"@prisma/client": "^6.6.0",
|
||||
"@radix-ui/react-avatar": "^1.1.3",
|
||||
"@radix-ui/react-checkbox": "^1.1.4",
|
||||
@@ -31,11 +36,11 @@
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^3.6.0",
|
||||
"jszip": "^3.10.1",
|
||||
"langchain": "^0.3.30",
|
||||
"lucide-react": "^0.475.0",
|
||||
"mime-types": "^3.0.1",
|
||||
"next": "^15.2.4",
|
||||
"next-themes": "^0.4.4",
|
||||
"openai": "^4.85.4",
|
||||
"pdf2pic": "^3.1.4",
|
||||
"react": "^19.0.0",
|
||||
"react-day-picker": "^8.10.1",
|
||||
@@ -364,6 +369,7 @@
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.2.5.tgz",
|
||||
"integrity": "sha512-uI2+/8h/zVsH8RrYdG8eUErbuGBk16rZKQfz8CjxQOyCE6v7BqFYEbFwvOkvl1KbUdxhqOnXp78+uE5h8qVEgQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"typescript": "^5.8.2",
|
||||
"uncrypto": "^0.1.3"
|
||||
@@ -374,6 +380,66 @@
|
||||
"resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.18.tgz",
|
||||
"integrity": "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="
|
||||
},
|
||||
"node_modules/@cfworker/json-schema": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.1.tgz",
|
||||
"integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@dnd-kit/accessibility": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
|
||||
"integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/core": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
||||
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dnd-kit/accessibility": "^3.1.1",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/sortable": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz",
|
||||
"integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@dnd-kit/core": "^6.3.0",
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/utilities": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
|
||||
"integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz",
|
||||
@@ -1035,6 +1101,15 @@
|
||||
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@google/generative-ai": {
|
||||
"version": "0.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz",
|
||||
"integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@hexagon/base64": {
|
||||
"version": "1.1.28",
|
||||
"resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz",
|
||||
@@ -1544,12 +1619,185 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/core": {
|
||||
"version": "0.3.63",
|
||||
"resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.63.tgz",
|
||||
"integrity": "sha512-CQfyu4WgwizUhSc1YsDDzzHga6WVhLqeuAyCD4VpGAPa3k3QI+H0b3ECFr/WjJMw0amMtHtfgPWMa1tS7P7qVg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@cfworker/json-schema": "^4.0.2",
|
||||
"ansi-styles": "^5.0.0",
|
||||
"camelcase": "6",
|
||||
"decamelize": "1.2.0",
|
||||
"js-tiktoken": "^1.0.12",
|
||||
"langsmith": "^0.3.33",
|
||||
"mustache": "^4.2.0",
|
||||
"p-queue": "^6.6.2",
|
||||
"p-retry": "4",
|
||||
"uuid": "^10.0.0",
|
||||
"zod": "^3.25.32",
|
||||
"zod-to-json-schema": "^3.22.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/core/node_modules/ansi-styles": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/core/node_modules/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/google-genai": {
|
||||
"version": "0.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@langchain/google-genai/-/google-genai-0.2.14.tgz",
|
||||
"integrity": "sha512-gKe/T2LNh8wSSMJOaFmYd8cwQnDSXKtVtC6a7CFoq5nWuh0bKzhItM/7bue1aMN8mlKfB2G1HCwxhaZoSpS/DA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@google/generative-ai": "^0.24.0",
|
||||
"uuid": "^11.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@langchain/core": ">=0.3.58 <0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/google-genai/node_modules/uuid": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
||||
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/esm/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/mistralai": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@langchain/mistralai/-/mistralai-0.2.1.tgz",
|
||||
"integrity": "sha512-s91BlNcuxaaZGnVukyl81nwGrWpeE0EYiAdEFoBmZwlT4yLpx+QpPhRsGKrTg/Vm7Nscy6Wd8Xy2PJ93wftMdw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mistralai/mistralai": "^1.3.1",
|
||||
"uuid": "^10.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@langchain/core": ">=0.3.58 <0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/mistralai/node_modules/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/openai": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.6.1.tgz",
|
||||
"integrity": "sha512-jm8MzMEjAKPReYma4Lewb9vGnocKbhoClqPuRTxtKPDgqQ5yJWSisNy4iZO/a1d6ag/7MnxwKMjVsJdy1cBsxw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tiktoken": "^1.0.12",
|
||||
"openai": "^5.3.0",
|
||||
"zod": "^3.25.32"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@langchain/core": ">=0.3.58 <0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/openai/node_modules/openai": {
|
||||
"version": "5.9.2",
|
||||
"resolved": "https://registry.npmjs.org/openai/-/openai-5.9.2.tgz",
|
||||
"integrity": "sha512-d7t/lRkwZpSwIk7GW3EHRSGAlsuoi1WL6VhCO02raEzZO2ahEVAbWn3WmOcpeh9zF6xF9weJXoVeDkWJRz+SHA==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"openai": "bin/cli"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ws": "^8.18.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"ws": {
|
||||
"optional": true
|
||||
},
|
||||
"zod": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@langchain/textsplitters": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@langchain/textsplitters/-/textsplitters-0.1.0.tgz",
|
||||
"integrity": "sha512-djI4uw9rlkAb5iMhtLED+xJebDdAG935AdP4eRTB02R7OB/act55Bj9wsskhZsvuyQRpO4O1wQOp85s6T6GWmw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tiktoken": "^1.0.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@langchain/core": ">=0.2.21 <0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@levischuck/tiny-cbor": {
|
||||
"version": "0.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@levischuck/tiny-cbor/-/tiny-cbor-0.2.11.tgz",
|
||||
"integrity": "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@mistralai/mistralai": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.7.4.tgz",
|
||||
"integrity": "sha512-wty9hHEvIJ5RS8+75NY+a1zXtCCqYQgI26e8R2N7O9ZvD16ep2kF6ciJD2EiWOgS/K+iycRGsrI3nqgkPLG/Xw==",
|
||||
"dependencies": {
|
||||
"zod-to-json-schema": "^3.24.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": ">= 3"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.7.tgz",
|
||||
@@ -4124,9 +4372,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/bundler-plugin-core/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
@@ -4638,6 +4886,8 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
|
||||
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^4.0.0"
|
||||
@@ -4683,6 +4933,12 @@
|
||||
"@types/react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
||||
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/sharp": {
|
||||
"version": "0.31.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.31.1.tgz",
|
||||
@@ -4707,6 +4963,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.27.0.tgz",
|
||||
@@ -4846,9 +5108,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5280,6 +5542,8 @@
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
},
|
||||
@@ -5341,6 +5605,8 @@
|
||||
"resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
|
||||
"integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"humanize-ms": "^1.2.1"
|
||||
},
|
||||
@@ -5463,7 +5729,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true,
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/aria-hidden": {
|
||||
@@ -5693,7 +5958,9 @@
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.7",
|
||||
@@ -5758,9 +6025,10 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/better-auth": {
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.2.10.tgz",
|
||||
"integrity": "sha512-nEj1RG4DdLUuJiV5CR93ORyPCptGRBwksaPPCkUtGo9ka+UIlTpaiKoTaTqVLLYlqwX4bOj9tJ32oBNdf2G3Kg==",
|
||||
"version": "1.2.12",
|
||||
"resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.2.12.tgz",
|
||||
"integrity": "sha512-YicCyjQ+lxb7YnnaCewrVOjj3nPVa0xcfrOJK7k5MLMX9Mt9UnJ8GYaVQNHOHLyVxl92qc3C758X1ihqAUzm4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@better-auth/utils": "0.2.5",
|
||||
"@better-fetch/fetch": "^1.1.18",
|
||||
@@ -5770,16 +6038,16 @@
|
||||
"@simplewebauthn/server": "^13.0.0",
|
||||
"better-call": "^1.0.8",
|
||||
"defu": "^6.1.4",
|
||||
"jose": "^5.9.6",
|
||||
"jose": "^6.0.11",
|
||||
"kysely": "^0.28.2",
|
||||
"nanostores": "^0.11.3",
|
||||
"zod": "^3.24.1"
|
||||
}
|
||||
},
|
||||
"node_modules/better-call": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/better-call/-/better-call-1.0.11.tgz",
|
||||
"integrity": "sha512-MOM01EMZFMzApWq9+WfqAnl2+DzFoMNp4H+lTFE1p7WF4evMeaQAAcOhI1WwMjITV4PGIWJ3Vn5GciQ5VHXbIA==",
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/better-call/-/better-call-1.0.12.tgz",
|
||||
"integrity": "sha512-ssq5OfB9Ungv2M1WVrRnMBomB0qz1VKuhkY2WxjHaLtlsHoSe9EPolj1xf7xf8LY9o3vfk3Rx6rCWI4oVHeBRg==",
|
||||
"dependencies": {
|
||||
"@better-fetch/fetch": "^1.1.4",
|
||||
"rou3": "^0.5.1",
|
||||
@@ -5809,9 +6077,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5957,6 +6225,19 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
||||
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase-css": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||
@@ -5990,7 +6271,6 @@
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
@@ -6137,6 +6417,8 @@
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
@@ -6166,6 +6448,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/console-table-printer": {
|
||||
"version": "2.14.6",
|
||||
"resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.14.6.tgz",
|
||||
"integrity": "sha512-MCBl5HNVaFuuHW6FGbL/4fB7N/ormCy+tQ+sxTrF6QtSbSNETvPuOVbkJBhzDgYhvjWGrTma4eYJa37ZuoQsPw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"simple-wcswidth": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
@@ -6305,6 +6596,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
@@ -6368,6 +6669,8 @@
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
@@ -6678,6 +6981,7 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -7231,10 +7535,18 @@
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/eventemitter3": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/events": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
@@ -7436,6 +7748,8 @@
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -7450,13 +7764,17 @@
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
|
||||
"integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/form-data/node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -7466,6 +7784,8 @@
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
@@ -7478,6 +7798,8 @@
|
||||
"resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
|
||||
"integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"node-domexception": "1.0.0",
|
||||
"web-streams-polyfill": "4.0.0-beta.3"
|
||||
@@ -7678,9 +8000,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/glob/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
@@ -7849,6 +8171,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
@@ -7949,6 +8272,8 @@
|
||||
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
||||
"integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.0.0"
|
||||
}
|
||||
@@ -8556,14 +8881,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz",
|
||||
"integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==",
|
||||
"version": "6.0.12",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-6.0.12.tgz",
|
||||
"integrity": "sha512-T8xypXs8CpmiIi78k0E+Lk7T2zlK4zDyg+o1CZ4AkOHgDg98ogdP2BeZ61lTFKFyoEwJ9RgAgN+SdM3iPgNonQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tiktoken": {
|
||||
"version": "1.0.20",
|
||||
"resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.20.tgz",
|
||||
"integrity": "sha512-Xlaqhhs8VfCd6Sh7a1cFkZHQbYTLCwVJJWiHVxBYzLPxW0XsoxBy1hitmjkdIjD3Aon5BXLHFwU5O8WUx6HH+A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -8574,7 +8908,6 @@
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
@@ -8636,6 +8969,15 @@
|
||||
"json5": "lib/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonpointer": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
|
||||
"integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jsx-ast-utils": {
|
||||
"version": "3.3.5",
|
||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
||||
@@ -8678,10 +9020,167 @@
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.2.tgz",
|
||||
"integrity": "sha512-4YAVLoF0Sf0UTqlhgQMFU9iQECdah7n+13ANkiuVfRvlK+uI0Etbgd7bVP36dKlG+NXWbhGua8vnGt+sdhvT7A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/langchain": {
|
||||
"version": "0.3.30",
|
||||
"resolved": "https://registry.npmjs.org/langchain/-/langchain-0.3.30.tgz",
|
||||
"integrity": "sha512-UyVsfwHDpHbrnWrjWuhJHqi8Non+Zcsf2kdpDTqyJF8NXrHBOpjdHT5LvPuW9fnE7miDTWf5mLcrWAGZgcrznQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@langchain/openai": ">=0.1.0 <0.7.0",
|
||||
"@langchain/textsplitters": ">=0.0.0 <0.2.0",
|
||||
"js-tiktoken": "^1.0.12",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsonpointer": "^5.0.1",
|
||||
"langsmith": "^0.3.33",
|
||||
"openapi-types": "^12.1.3",
|
||||
"p-retry": "4",
|
||||
"uuid": "^10.0.0",
|
||||
"yaml": "^2.2.1",
|
||||
"zod": "^3.25.32"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@langchain/anthropic": "*",
|
||||
"@langchain/aws": "*",
|
||||
"@langchain/cerebras": "*",
|
||||
"@langchain/cohere": "*",
|
||||
"@langchain/core": ">=0.3.58 <0.4.0",
|
||||
"@langchain/deepseek": "*",
|
||||
"@langchain/google-genai": "*",
|
||||
"@langchain/google-vertexai": "*",
|
||||
"@langchain/google-vertexai-web": "*",
|
||||
"@langchain/groq": "*",
|
||||
"@langchain/mistralai": "*",
|
||||
"@langchain/ollama": "*",
|
||||
"@langchain/xai": "*",
|
||||
"axios": "*",
|
||||
"cheerio": "*",
|
||||
"handlebars": "^4.7.8",
|
||||
"peggy": "^3.0.2",
|
||||
"typeorm": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@langchain/anthropic": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/aws": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/cerebras": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/cohere": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/deepseek": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/google-genai": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/google-vertexai": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/google-vertexai-web": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/groq": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/mistralai": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/ollama": {
|
||||
"optional": true
|
||||
},
|
||||
"@langchain/xai": {
|
||||
"optional": true
|
||||
},
|
||||
"axios": {
|
||||
"optional": true
|
||||
},
|
||||
"cheerio": {
|
||||
"optional": true
|
||||
},
|
||||
"handlebars": {
|
||||
"optional": true
|
||||
},
|
||||
"peggy": {
|
||||
"optional": true
|
||||
},
|
||||
"typeorm": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/langchain/node_modules/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/langsmith": {
|
||||
"version": "0.3.46",
|
||||
"resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.3.46.tgz",
|
||||
"integrity": "sha512-Hhi4/cMjhWIGpu0DW5eQrXBbeeKQWPYYQyJCYzhFjod+xinMry4i8QR0gxrrgjGOgfMuU6nyK79YqjGTEPVbDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/uuid": "^10.0.0",
|
||||
"chalk": "^4.1.2",
|
||||
"console-table-printer": "^2.12.1",
|
||||
"p-queue": "^6.6.2",
|
||||
"p-retry": "4",
|
||||
"semver": "^7.6.3",
|
||||
"uuid": "^10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "*",
|
||||
"@opentelemetry/exporter-trace-otlp-proto": "*",
|
||||
"@opentelemetry/sdk-trace-base": "*",
|
||||
"openai": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@opentelemetry/api": {
|
||||
"optional": true
|
||||
},
|
||||
"@opentelemetry/exporter-trace-otlp-proto": {
|
||||
"optional": true
|
||||
},
|
||||
"@opentelemetry/sdk-trace-base": {
|
||||
"optional": true
|
||||
},
|
||||
"openai": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/langsmith/node_modules/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/language-subtag-registry": {
|
||||
"version": "0.3.23",
|
||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
|
||||
@@ -8997,6 +9496,16 @@
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mustache": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
|
||||
"integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"mustache": "bin/mustache"
|
||||
}
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
@@ -9162,6 +9671,8 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
@@ -9345,6 +9856,8 @@
|
||||
"resolved": "https://registry.npmjs.org/openai/-/openai-4.89.0.tgz",
|
||||
"integrity": "sha512-XNI0q2l8/Os6jmojxaID5EhyQjxZgzR2gWcpEjYWK5hGKwE7AcifxEY7UNwFDDHJQXqeiosQ0CJwQN+rvnwdjA==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/node-fetch": "^2.6.4",
|
||||
@@ -9375,6 +9888,8 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.81.tgz",
|
||||
"integrity": "sha512-7KO9oZ2//ivtSsryp0LQUqq79zyGXzwq1WqfywpC9ucjY7YyltMMmxWgtRFRKCxwa7VPxVBVy4kHf5UC1E8Lug==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
@@ -9383,6 +9898,14 @@
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/openapi-types": {
|
||||
"version": "12.1.3",
|
||||
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
|
||||
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
@@ -9421,6 +9944,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/p-finally": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
"integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
@@ -9451,6 +9983,47 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-queue": {
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
|
||||
"integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"eventemitter3": "^4.0.4",
|
||||
"p-timeout": "^3.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-retry": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
|
||||
"integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/retry": "0.12.0",
|
||||
"retry": "^0.13.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/p-timeout": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
|
||||
"integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"p-finally": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/package-json-from-dist": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
@@ -10283,6 +10856,15 @@
|
||||
"integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
|
||||
"integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
|
||||
@@ -10773,6 +11355,12 @@
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-wcswidth": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.1.2.tgz",
|
||||
"integrity": "sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/slugify": {
|
||||
"version": "1.6.6",
|
||||
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
|
||||
@@ -11777,6 +12365,8 @@
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
@@ -12161,13 +12751,22 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.24.2",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
|
||||
"integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
|
||||
"version": "3.25.76",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
},
|
||||
"node_modules/zod-to-json-schema": {
|
||||
"version": "3.24.6",
|
||||
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz",
|
||||
"integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"zod": "^3.24.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,13 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@fast-csv/format": "^5.0.2",
|
||||
"@fast-csv/parse": "^5.0.2",
|
||||
"@langchain/google-genai": "^0.2.14",
|
||||
"@langchain/mistralai": "^0.2.1",
|
||||
"@langchain/openai": "^0.6.1",
|
||||
"@prisma/client": "^6.6.0",
|
||||
"@radix-ui/react-avatar": "^1.1.3",
|
||||
"@radix-ui/react-checkbox": "^1.1.4",
|
||||
@@ -33,11 +38,11 @@
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^3.6.0",
|
||||
"jszip": "^3.10.1",
|
||||
"langchain": "^0.3.30",
|
||||
"lucide-react": "^0.475.0",
|
||||
"mime-types": "^3.0.1",
|
||||
"next": "^15.2.4",
|
||||
"next-themes": "^0.4.4",
|
||||
"openai": "^4.85.4",
|
||||
"pdf2pic": "^3.1.4",
|
||||
"react": "^19.0.0",
|
||||
"react-day-picker": "^8.10.1",
|
||||
|
||||
1
public/logo/google.svg
Normal file
1
public/logo/google.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Gemini</title><defs><linearGradient id="lobe-icons-gemini-fill" x1="0%" x2="68.73%" y1="100%" y2="30.395%"><stop offset="0%" stop-color="#1C7DFF"></stop><stop offset="52.021%" stop-color="#1C69FF"></stop><stop offset="100%" stop-color="#F0DCD6"></stop></linearGradient></defs><path d="M12 24A14.304 14.304 0 000 12 14.304 14.304 0 0012 0a14.305 14.305 0 0012 12 14.305 14.305 0 00-12 12" fill="url(#lobe-icons-gemini-fill)" fill-rule="nonzero"></path></svg>
|
||||
|
After Width: | Height: | Size: 570 B |
1
public/logo/mistral.svg
Normal file
1
public/logo/mistral.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" viewBox="0 0 256 233"><path d="M186.18182 0h46.54545v46.54545h-46.54545z"/><path fill="#F7D046" d="M209.45454 0h46.54545v46.54545h-46.54545z"/><path d="M0 0h46.54545v46.54545H0zM0 46.54545h46.54545V93.0909H0zM0 93.09091h46.54545v46.54545H0zM0 139.63636h46.54545v46.54545H0zM0 186.18182h46.54545v46.54545H0z"/><path fill="#F7D046" d="M23.27273 0h46.54545v46.54545H23.27273z"/><path fill="#F2A73B" d="M209.45454 46.54545h46.54545V93.0909h-46.54545zM23.27273 46.54545h46.54545V93.0909H23.27273z"/><path d="M139.63636 46.54545h46.54545V93.0909h-46.54545z"/><path fill="#F2A73B" d="M162.90909 46.54545h46.54545V93.0909h-46.54545zM69.81818 46.54545h46.54545V93.0909H69.81818z"/><path fill="#EE792F" d="M116.36364 93.09091h46.54545v46.54545h-46.54545zM162.90909 93.09091h46.54545v46.54545h-46.54545zM69.81818 93.09091h46.54545v46.54545H69.81818z"/><path d="M93.09091 139.63636h46.54545v46.54545H93.09091z"/><path fill="#EB5829" d="M116.36364 139.63636h46.54545v46.54545h-46.54545z"/><path fill="#EE792F" d="M209.45454 93.09091h46.54545v46.54545h-46.54545zM23.27273 93.09091h46.54545v46.54545H23.27273z"/><path d="M186.18182 139.63636h46.54545v46.54545h-46.54545z"/><path fill="#EB5829" d="M209.45454 139.63636h46.54545v46.54545h-46.54545z"/><path d="M186.18182 186.18182h46.54545v46.54545h-46.54545z"/><path fill="#EB5829" d="M23.27273 139.63636h46.54545v46.54545H23.27273z"/><path fill="#EA3326" d="M209.45454 186.18182h46.54545v46.54545h-46.54545zM23.27273 186.18182h46.54545v46.54545H23.27273z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
public/logo/openai.svg
Normal file
1
public/logo/openai.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="260" preserveAspectRatio="xMidYMid" viewBox="0 0 256 260"><path d="M239.184 106.203a64.716 64.716 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.716 64.716 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.665 64.665 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.767 64.767 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483Zm-97.56 136.338a48.397 48.397 0 0 1-31.105-11.255l1.535-.87 51.67-29.825a8.595 8.595 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601Zm-104.466-44.61a48.345 48.345 0 0 1-5.781-32.589l1.534.921 51.722 29.826a8.339 8.339 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803ZM23.549 85.38a48.499 48.499 0 0 1 25.58-21.333v61.39a8.288 8.288 0 0 0 4.195 7.316l62.874 36.272-21.845 12.636a.819.819 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405v.256Zm179.466 41.695-63.08-36.63L161.73 77.86a.819.819 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.544 8.544 0 0 0-4.4-7.213Zm21.742-32.69-1.535-.922-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.716.716 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391v.205ZM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87-51.67 29.825a8.595 8.595 0 0 0-4.246 7.367l-.051 72.697Zm11.868-25.58 28.138-16.217 28.188 16.218v32.434l-28.086 16.218-28.188-16.218-.052-32.434Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
Reference in New Issue
Block a user