refactor: make requests purely client-side
This commit is contained in:
@ -1,7 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { parsePartialJson } from '@ai-sdk/ui-utils'
|
import { generateFeedback } from '~/lib/feedback'
|
||||||
import { useChat } from '@ai-sdk/vue'
|
|
||||||
import { isObject } from '@vueuse/core'
|
|
||||||
|
|
||||||
export interface ResearchFeedbackResult {
|
export interface ResearchFeedbackResult {
|
||||||
assistantQuestion: string
|
assistantQuestion: string
|
||||||
@ -18,9 +16,8 @@
|
|||||||
|
|
||||||
const feedback = ref<ResearchFeedbackResult[]>([])
|
const feedback = ref<ResearchFeedbackResult[]>([])
|
||||||
|
|
||||||
const { messages, input, error, handleSubmit, isLoading } = useChat({
|
const isLoading = ref(false)
|
||||||
api: '/api/generate-feedback',
|
const error = ref('')
|
||||||
})
|
|
||||||
|
|
||||||
const isSubmitButtonDisabled = computed(
|
const isSubmitButtonDisabled = computed(
|
||||||
() =>
|
() =>
|
||||||
@ -34,67 +31,37 @@
|
|||||||
|
|
||||||
async function getFeedback(query: string, numQuestions = 3) {
|
async function getFeedback(query: string, numQuestions = 3) {
|
||||||
clear()
|
clear()
|
||||||
// Set input value. (This only makes sure that the library sends the request)
|
isLoading.value = true
|
||||||
input.value = query
|
try {
|
||||||
handleSubmit(
|
for await (const f of generateFeedback({
|
||||||
{},
|
query,
|
||||||
{
|
numQuestions,
|
||||||
body: {
|
})) {
|
||||||
query,
|
const questions = f.questions!.filter((s) => typeof s === 'string')
|
||||||
numQuestions,
|
// Incrementally update modelValue
|
||||||
},
|
for (let i = 0; i < questions.length; i += 1) {
|
||||||
},
|
if (feedback.value[i]) {
|
||||||
)
|
feedback.value[i].assistantQuestion = questions[i]
|
||||||
}
|
} else {
|
||||||
function clear() {
|
feedback.value.push({
|
||||||
messages.value = []
|
assistantQuestion: questions[i],
|
||||||
input.value = ''
|
userAnswer: '',
|
||||||
error.value = undefined
|
})
|
||||||
feedback.value = []
|
}
|
||||||
}
|
|
||||||
|
|
||||||
watch(messages, (m) => {
|
|
||||||
const assistantMessage = m[m.length - 1]
|
|
||||||
if (assistantMessage?.role !== 'assistant') {
|
|
||||||
return {
|
|
||||||
value: undefined,
|
|
||||||
state: 'undefined-input',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = removeJsonMarkdown(assistantMessage.content)
|
|
||||||
// Write the questions into modelValue
|
|
||||||
const parseResult = parsePartialJson(content)
|
|
||||||
|
|
||||||
if (parseResult.state === 'repaired-parse' || parseResult.state === 'successful-parse') {
|
|
||||||
if (!isObject(parseResult.value) || Array.isArray(parseResult.value)) {
|
|
||||||
return (feedback.value = [])
|
|
||||||
}
|
|
||||||
const unsafeQuestions = parseResult.value.questions
|
|
||||||
if (!unsafeQuestions || !Array.isArray(unsafeQuestions)) return (feedback.value = [])
|
|
||||||
|
|
||||||
const questions = unsafeQuestions.filter((s) => typeof s === 'string')
|
|
||||||
// Incrementally update modelValue
|
|
||||||
for (let i = 0; i < questions.length; i += 1) {
|
|
||||||
if (feedback.value[i]) {
|
|
||||||
feedback.value[i].assistantQuestion = questions[i]
|
|
||||||
} else {
|
|
||||||
feedback.value.push({
|
|
||||||
assistantQuestion: questions[i],
|
|
||||||
userAnswer: '',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} catch (e: any) {
|
||||||
feedback.value = []
|
console.error('Error getting feedback:', e)
|
||||||
|
error.value = e.message
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
watch(error, (e) => {
|
function clear() {
|
||||||
if (e) {
|
feedback.value = []
|
||||||
console.error(`ResearchFeedback error,`, e)
|
error.value = ''
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
getFeedback,
|
getFeedback,
|
||||||
@ -111,6 +78,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
|
<p v-if="error" class="text-red-500">{{ error }}</p>
|
||||||
<div v-if="!feedback.length && !error">Waiting for model feedback...</div>
|
<div v-if="!feedback.length && !error">Waiting for model feedback...</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div v-if="error" class="text-red-500">{{ error }}</div>
|
<div v-if="error" class="text-red-500">{{ error }}</div>
|
||||||
|
@ -19,7 +19,7 @@ export interface WriteFinalReportParams {
|
|||||||
prompt: string;
|
prompt: string;
|
||||||
learnings: string[];
|
learnings: string[];
|
||||||
}
|
}
|
||||||
|
// useRuntimeConfig()
|
||||||
// Used for streaming response
|
// Used for streaming response
|
||||||
export type SearchQuery = z.infer<typeof searchQueriesTypeSchema>['queries'][0];
|
export type SearchQuery = z.infer<typeof searchQueriesTypeSchema>['queries'][0];
|
||||||
export type PartialSearchQuery = DeepPartial<SearchQuery>;
|
export type PartialSearchQuery = DeepPartial<SearchQuery>;
|
||||||
|
@ -5,6 +5,8 @@ import { zodToJsonSchema } from 'zod-to-json-schema'
|
|||||||
import { o3MiniModel } from './ai/providers';
|
import { o3MiniModel } from './ai/providers';
|
||||||
import { systemPrompt } from './prompt';
|
import { systemPrompt } from './prompt';
|
||||||
|
|
||||||
|
type PartialFeedback = DeepPartial<z.infer<typeof feedbackTypeSchema>>
|
||||||
|
|
||||||
export const feedbackTypeSchema = z.object({
|
export const feedbackTypeSchema = z.object({
|
||||||
questions: z.array(z.string())
|
questions: z.array(z.string())
|
||||||
})
|
})
|
||||||
@ -28,10 +30,16 @@ export function generateFeedback({
|
|||||||
`Given the following query from the user, ask some follow up questions to clarify the research direction. Return a maximum of ${numQuestions} questions, but feel free to return less if the original query is clear: <query>${query}</query>`,
|
`Given the following query from the user, ask some follow up questions to clarify the research direction. Return a maximum of ${numQuestions} questions, but feel free to return less if the original query is clear: <query>${query}</query>`,
|
||||||
`You MUST respond in JSON with the following schema: ${jsonSchema}`,
|
`You MUST respond in JSON with the following schema: ${jsonSchema}`,
|
||||||
].join('\n\n');
|
].join('\n\n');
|
||||||
return streamText({
|
|
||||||
|
const stream = streamText({
|
||||||
model: o3MiniModel,
|
model: o3MiniModel,
|
||||||
system: systemPrompt(),
|
system: systemPrompt(),
|
||||||
prompt,
|
prompt,
|
||||||
});
|
});
|
||||||
// return userFeedback.object.questions.slice(0, numQuestions);
|
|
||||||
|
return parseStreamingJson(
|
||||||
|
stream.textStream,
|
||||||
|
feedbackTypeSchema,
|
||||||
|
(value: PartialFeedback) => !!value.questions && value.questions.length > 0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// This file is currently unused
|
||||||
import { generateFeedback } from "~/lib/feedback";
|
import { generateFeedback } from "~/lib/feedback";
|
||||||
|
|
||||||
export default defineEventHandler(async event => {
|
export default defineEventHandler(async event => {
|
||||||
|
Reference in New Issue
Block a user