feat: config manager modal
This commit is contained in:
@ -3,33 +3,19 @@ import { getEncoding } from 'js-tiktoken'
|
||||
|
||||
import { RecursiveCharacterTextSplitter } from './text-splitter'
|
||||
|
||||
// Providers
|
||||
const openai = createOpenAI({
|
||||
apiKey: import.meta.env.VITE_OPENAI_API_KEY!,
|
||||
baseURL: import.meta.env.VITE_OPENAI_ENDPOINT || 'https://api.openai.com/v1',
|
||||
})
|
||||
|
||||
const customModel = import.meta.env.VITE_OPENAI_MODEL || 'o3-mini'
|
||||
|
||||
// Models
|
||||
|
||||
export const o3MiniModel = openai(customModel, {
|
||||
// reasoningEffort: customModel.startsWith('o') ? 'medium' : undefined,
|
||||
structuredOutputs: true,
|
||||
})
|
||||
|
||||
const MinChunkSize = 140
|
||||
const encoder = getEncoding('o200k_base')
|
||||
|
||||
// trim prompt to maximum context size
|
||||
export function trimPrompt(
|
||||
prompt: string,
|
||||
contextSize = Number(import.meta.env.VITE_CONTEXT_SIZE) || 128_000,
|
||||
) {
|
||||
export function trimPrompt(prompt: string, contextSize?: number) {
|
||||
if (!prompt) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (!contextSize) {
|
||||
contextSize = useConfigStore().config.ai.contextSize || 128_000
|
||||
}
|
||||
|
||||
const length = encoder.encode(prompt).length
|
||||
if (length <= contextSize) {
|
||||
return prompt
|
||||
|
@ -1,13 +1,15 @@
|
||||
import { generateObject, streamText } from 'ai'
|
||||
import { streamText } from 'ai'
|
||||
import { compact } from 'lodash-es'
|
||||
import pLimit from 'p-limit'
|
||||
import { z } from 'zod'
|
||||
import { parseStreamingJson, type DeepPartial } from '~/utils/json'
|
||||
|
||||
import { o3MiniModel, trimPrompt } from './ai/providers'
|
||||
import { trimPrompt } from './ai/providers'
|
||||
import { systemPrompt } from './prompt'
|
||||
import zodToJsonSchema from 'zod-to-json-schema'
|
||||
import { tavily, type TavilySearchResponse } from '@tavily/core'
|
||||
import { type TavilySearchResponse } from '@tavily/core'
|
||||
import { useTavily } from '~/composables/useTavily'
|
||||
import { useAiModel } from '~/composables/useAiProvider'
|
||||
|
||||
export type ResearchResult = {
|
||||
learnings: string[]
|
||||
@ -53,16 +55,6 @@ export type ResearchStep =
|
||||
// increase this if you have higher API rate limits
|
||||
const ConcurrencyLimit = 2
|
||||
|
||||
// Initialize Firecrawl with optional API key and optional base url
|
||||
|
||||
// const firecrawl = new FirecrawlApp({
|
||||
// apiKey: process.env.FIRECRAWL_KEY ?? '',
|
||||
// apiUrl: process.env.FIRECRAWL_BASE_URL,
|
||||
// });
|
||||
const tvly = tavily({
|
||||
apiKey: import.meta.env.VITE_TAVILY_API_KEY ?? '',
|
||||
})
|
||||
|
||||
/**
|
||||
* Schema for {@link generateSearchQueries} without dynamic descriptions
|
||||
*/
|
||||
@ -105,12 +97,14 @@ export function generateSearchQueries({
|
||||
const prompt = [
|
||||
`Given the following prompt from the user, generate a list of SERP queries to research the topic. Return a maximum of ${numQueries} queries, but feel free to return less if the original prompt is clear. Make sure each query is unique and not similar to each other: <prompt>${query}</prompt>\n\n`,
|
||||
learnings
|
||||
? `Here are some learnings from previous research, use them to generate more specific queries: ${learnings.join('\n')}`
|
||||
? `Here are some learnings from previous research, use them to generate more specific queries: ${learnings.join(
|
||||
'\n',
|
||||
)}`
|
||||
: '',
|
||||
`You MUST respond in JSON with the following schema: ${jsonSchema}`,
|
||||
].join('\n\n')
|
||||
return streamText({
|
||||
model: o3MiniModel,
|
||||
model: useAiModel(),
|
||||
system: systemPrompt(),
|
||||
prompt,
|
||||
})
|
||||
@ -147,12 +141,14 @@ function processSearchResult({
|
||||
)
|
||||
const prompt = [
|
||||
`Given the following contents from a SERP search for the query <query>${query}</query>, generate a list of learnings from the contents. Return a maximum of ${numLearnings} learnings, but feel free to return less if the contents are clear. Make sure each learning is unique and not similar to each other. The learnings should be concise and to the point, as detailed and information dense as possible. Make sure to include any entities like people, places, companies, products, things, etc in the learnings, as well as any exact metrics, numbers, or dates. The learnings will be used to research the topic further.`,
|
||||
`<contents>${contents.map((content) => `<content>\n${content}\n</content>`).join('\n')}</contents>`,
|
||||
`<contents>${contents
|
||||
.map((content) => `<content>\n${content}\n</content>`)
|
||||
.join('\n')}</contents>`,
|
||||
`You MUST respond in JSON with the following schema: ${jsonSchema}`,
|
||||
].join('\n\n')
|
||||
|
||||
return streamText({
|
||||
model: o3MiniModel,
|
||||
model: useAiModel(),
|
||||
abortSignal: AbortSignal.timeout(60_000),
|
||||
system: systemPrompt(),
|
||||
prompt,
|
||||
@ -179,7 +175,7 @@ export function writeFinalReport({
|
||||
].join('\n\n')
|
||||
|
||||
return streamText({
|
||||
model: o3MiniModel,
|
||||
model: useAiModel(),
|
||||
system: systemPrompt(),
|
||||
prompt: _prompt,
|
||||
})
|
||||
@ -263,7 +259,7 @@ export async function deepResearch({
|
||||
// limit: 5,
|
||||
// scrapeOptions: { formats: ['markdown'] },
|
||||
// });
|
||||
const result = await tvly.search(searchQuery.query, {
|
||||
const result = await useTavily().search(searchQuery.query, {
|
||||
maxResults: 5,
|
||||
})
|
||||
console.log(
|
||||
@ -331,7 +327,9 @@ export async function deepResearch({
|
||||
|
||||
const nextQuery = `
|
||||
Previous research goal: ${searchQuery.researchGoal}
|
||||
Follow-up research directions: ${searchResult.followUpQuestions.map((q) => `\n${q}`).join('')}
|
||||
Follow-up research directions: ${searchResult.followUpQuestions
|
||||
.map((q) => `\n${q}`)
|
||||
.join('')}
|
||||
`.trim()
|
||||
|
||||
return deepResearch({
|
||||
|
@ -2,8 +2,8 @@ import { streamText } from 'ai'
|
||||
import { z } from 'zod'
|
||||
import { zodToJsonSchema } from 'zod-to-json-schema'
|
||||
|
||||
import { o3MiniModel } from './ai/providers'
|
||||
import { systemPrompt } from './prompt'
|
||||
import { useAiModel } from '~/composables/useAiProvider'
|
||||
|
||||
type PartialFeedback = DeepPartial<z.infer<typeof feedbackTypeSchema>>
|
||||
|
||||
@ -32,7 +32,7 @@ export function generateFeedback({
|
||||
].join('\n\n')
|
||||
|
||||
const stream = streamText({
|
||||
model: o3MiniModel,
|
||||
model: useAiModel(),
|
||||
system: systemPrompt(),
|
||||
prompt,
|
||||
})
|
||||
|
Reference in New Issue
Block a user