Improve fine-tuning

pull/8341/head
Kamran Ahmed 4 weeks ago
parent 98d8510b60
commit 340ae002ca
  1. 49
      src/components/GenerateCourse/AICourse.tsx
  2. 44
      src/components/GenerateCourse/FineTuneCourse.tsx
  3. 44
      src/components/GenerateCourse/GenerateAICourse.tsx
  4. 9
      src/helper/generate-ai-course.ts
  5. 39
      src/lib/ai.ts

@ -1,10 +1,15 @@
import { SearchIcon, WandIcon } from 'lucide-react';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { cn } from '../../lib/classname';
import { isLoggedIn } from '../../lib/jwt';
import { showLoginPopup } from '../../lib/popup';
import { UserCoursesList } from './UserCoursesList';
import { FineTuneCourse } from './FineTuneCourse';
import {
getCourseFineTuneData,
getLastSessionId,
storeFineTuneData,
} from '../../lib/ai';
export const difficultyLevels = [
'beginner',
@ -19,6 +24,27 @@ export function AICourse(props: AICourseProps) {
const [keyword, setKeyword] = useState('');
const [difficulty, setDifficulty] = useState<DifficultyLevel>('beginner');
const [hasFineTuneData, setHasFineTuneData] = useState(false);
const [about, setAbout] = useState('');
const [goal, setGoal] = useState('');
const [customInstructions, setCustomInstructions] = useState('');
useEffect(() => {
const lastSessionId = getLastSessionId();
if (!lastSessionId) {
return;
}
const fineTuneData = getCourseFineTuneData(lastSessionId);
if (!fineTuneData) {
return;
}
// setAbout(fineTuneData.about);
// setGoal(fineTuneData.goal);
// setCustomInstructions(fineTuneData.customInstructions);
}, []);
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' && keyword.trim()) {
onSubmit();
@ -31,7 +57,15 @@ export function AICourse(props: AICourseProps) {
return;
}
window.location.href = `/ai-tutor/search?term=${encodeURIComponent(keyword)}&difficulty=${difficulty}`;
const sessionId = hasFineTuneData
? storeFineTuneData({
about,
goal,
customInstructions,
})
: '';
window.location.href = `/ai-tutor/search?term=${encodeURIComponent(keyword)}&difficulty=${difficulty}&id=${sessionId}`;
}
return (
@ -99,7 +133,16 @@ export function AICourse(props: AICourseProps) {
</div>
</div>
<FineTuneCourse />
<FineTuneCourse
hasFineTuneData={hasFineTuneData}
setHasFineTuneData={setHasFineTuneData}
about={about}
goal={goal}
customInstructions={customInstructions}
setAbout={setAbout}
setGoal={setGoal}
setCustomInstructions={setCustomInstructions}
/>
<button
type="submit"

@ -14,7 +14,7 @@ function Question(props: QuestionProps) {
return (
<div className="flex flex-col">
<label className="bg-gray-100 border-y px-4 py-2.5 text-sm font-medium text-gray-700">
<label className="border-y bg-gray-100 px-4 py-2.5 text-sm font-medium text-gray-700">
{label}
</label>
<textarea
@ -28,26 +28,46 @@ function Question(props: QuestionProps) {
);
}
export function FineTuneCourse() {
const [isFineTuning, setIsFineTuning] = useState(false);
type FineTuneCourseProps = {
hasFineTuneData: boolean;
about: string;
goal: string;
customInstructions: string;
const [about, setAbout] = useState('');
const [goal, setGoal] = useState('');
const [customInstructions, setCustomInstructions] = useState('');
setHasFineTuneData: (hasMetadata: boolean) => void;
setAbout: (about: string) => void;
setGoal: (goal: string) => void;
setCustomInstructions: (customInstructions: string) => void;
};
export function FineTuneCourse(props: FineTuneCourseProps) {
const {
about,
goal,
customInstructions,
hasFineTuneData,
setAbout,
setGoal,
setCustomInstructions,
setHasFineTuneData,
} = props;
return (
<div className="flex flex-col overflow-hidden rounded-lg border border-gray-200 transition-all">
<label
className={cn(
'group flex cursor-pointer select-none flex-row items-center gap-2.5 px-4 py-3 text-left text-gray-500 transition-colors hover:bg-gray-100 focus:outline-none',
isFineTuning && 'bg-gray-100',
hasFineTuneData && 'bg-gray-100',
)}
>
<input
id="fine-tune-checkbox"
type="checkbox"
className="h-4 w-4 group-hover:fill-current"
onChange={() => setIsFineTuning(!isFineTuning)}
checked={hasFineTuneData}
onChange={() => {
setHasFineTuneData(!hasFineTuneData);
}}
/>
Tell us more to tailor the course (optional){' '}
<span className="ml-auto rounded-md bg-gray-400 px-2 py-0.5 text-xs text-white">
@ -55,24 +75,24 @@ export function FineTuneCourse() {
</span>
</label>
{isFineTuning && (
{hasFineTuneData && (
<div className="mt-0 flex flex-col">
<Question
label="Tell us about your self"
placeholder="e.g. I have a background in marketing and I already have some basic knowledge of coding."
placeholder="e.g. I am a frontend developer and have good knowledge of HTML, CSS, and JavaScript."
value={about}
onChange={setAbout}
autoFocus={true}
/>
<Question
label="What is your goal with this course?"
placeholder="e.g. I want to learn about advanced topics with focus on practical examples."
placeholder="e.g. I want to be able to build Node.js APIs with Express.js and MongoDB."
value={goal}
onChange={setGoal}
/>
<Question
label="Custom Instructions (Optional)"
placeholder="Give instructions to the AI as if you were giving them to a friend."
placeholder="Give additional instructions to the AI as if you were giving them to a friend."
value={customInstructions}
onChange={setCustomInstructions}
/>

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { getUrlParams } from '../../lib/browser';
import { isLoggedIn } from '../../lib/jwt';
import { type AiCourse } from '../../lib/ai';
import { getCourseFineTuneData, type AiCourse } from '../../lib/ai';
import { AICourseContent } from './AICourseContent';
import { generateCourse } from '../../helper/generate-ai-course';
import { useQuery } from '@tanstack/react-query';
@ -13,6 +13,10 @@ type GenerateAICourseProps = {};
export function GenerateAICourse(props: GenerateAICourseProps) {
const [term, setTerm] = useState('');
const [difficulty, setDifficulty] = useState('');
const [sessionId, setSessionId] = useState('');
const [goal, setGoal] = useState('');
const [about, setAbout] = useState('');
const [customInstructions, setCustomInstructions] = useState('');
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState('');
@ -54,16 +58,47 @@ export function GenerateAICourse(props: GenerateAICourseProps) {
setTerm(paramsTerm);
setDifficulty(paramsDifficulty);
handleGenerateCourse({ term: paramsTerm, difficulty: paramsDifficulty });
const sessionId = params?.id;
setSessionId(sessionId);
let paramsGoal = '';
let paramsAbout = '';
let paramsCustomInstructions = '';
if (sessionId) {
const fineTuneData = getCourseFineTuneData(sessionId);
if (fineTuneData) {
paramsGoal = fineTuneData.goal;
paramsAbout = fineTuneData.about;
paramsCustomInstructions = fineTuneData.customInstructions;
setGoal(paramsGoal);
setAbout(paramsAbout);
setCustomInstructions(paramsCustomInstructions);
}
}
handleGenerateCourse({
term: paramsTerm,
difficulty: paramsDifficulty,
instructions: paramsCustomInstructions,
goal: paramsGoal,
about: paramsAbout,
});
}, [term, difficulty]);
const handleGenerateCourse = async (options: {
term: string;
difficulty: string;
instructions?: string;
goal?: string;
about?: string;
isForce?: boolean;
prompt?: string;
}) => {
const { term, difficulty, isForce, prompt } = options;
const { term, difficulty, isForce, prompt, instructions, goal, about } =
options;
if (!isLoggedIn()) {
window.location.href = '/ai-tutor';
@ -79,6 +114,9 @@ export function GenerateAICourse(props: GenerateAICourseProps) {
onCourseChange: setCourse,
onLoadingChange: setIsLoading,
onError: setError,
instructions,
goal,
about,
isForce,
prompt,
});

@ -12,6 +12,9 @@ type GenerateCourseOptions = {
slug?: string;
isForce?: boolean;
prompt?: string;
instructions?: string;
goal?: string;
about?: string;
onCourseIdChange?: (courseId: string) => void;
onCourseSlugChange?: (courseSlug: string) => void;
onCourseChange?: (course: AiCourse, rawData: string) => void;
@ -31,6 +34,9 @@ export async function generateCourse(options: GenerateCourseOptions) {
onError,
isForce = false,
prompt,
instructions,
goal,
about,
} = options;
onLoadingChange?.(true);
@ -76,6 +82,9 @@ export async function generateCourse(options: GenerateCourseOptions) {
difficulty,
isForce,
customPrompt: prompt,
instructions,
goal,
about,
}),
credentials: 'include',
},

@ -55,6 +55,45 @@ export function generateAiCourseStructure(
};
}
type CourseFineTuneData = {
about: string;
goal: string;
customInstructions: string;
};
export function storeFineTuneData(meta: CourseFineTuneData) {
const sessionId = Date.now().toString();
sessionStorage.setItem(sessionId, JSON.stringify(meta));
sessionStorage.setItem('lastSessionId', sessionId);
return sessionId;
}
export function getCourseFineTuneData(
sessionId: string,
): CourseFineTuneData | null {
const meta = sessionStorage.getItem(sessionId);
if (!meta) {
return null;
}
return JSON.parse(meta);
}
export function getLastSessionId(): string | null {
return sessionStorage.getItem('lastSessionId');
}
export function clearFineTuneData() {
const sessionId = getLastSessionId();
if (sessionId) {
sessionStorage.removeItem(sessionId);
}
sessionStorage.removeItem('lastSessionId');
}
const NEW_LINE = '\n'.charCodeAt(0);
export async function readAIRoadmapStream(

Loading…
Cancel
Save