File size: 4,045 Bytes
8e0957b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
import { useEffect, useState } from 'react';
import { CONFIG } from '../config';
import { getPromptGeneratePodcastScript } from '../utils/prompts';
import { getSSEStreamAsync } from '../utils/utils';
interface SplitContent {
thought: string;
codeBlock: string;
}
const getFromTo = (content: string, from: string, to: string): string => {
const firstSplit = content.split(from, 2);
if (firstSplit[1] !== undefined) {
const secondSplit = firstSplit[1].split(to, 1);
return secondSplit[0];
} else {
return '';
}
};
const splitContent = (content: string): SplitContent => {
return {
thought: getFromTo(content, '<think>', '</think>').trim(),
codeBlock: getFromTo(content, '```yaml', '```').trim(),
};
};
export const ScriptMaker = ({
setScript,
setBusy,
busy,
}: {
setScript: (script: string) => void;
setBusy: (busy: boolean) => void;
busy: boolean;
}) => {
const [input, setInput] = useState<string>('');
const [note, setNote] = useState<string>('');
const [thought, setThought] = useState<string>('');
const [isGenerating, setIsGenerating] = useState<boolean>(false);
useEffect(() => {
setBusy(isGenerating);
}, [isGenerating]);
const generate = async () => {
setIsGenerating(true);
setThought('');
try {
let responseContent = '';
const fetchResponse = await fetch(CONFIG.llmEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
messages: [
{
role: 'user',
content: getPromptGeneratePodcastScript(input, note),
},
],
temperature: 0.3,
stream: true,
}),
});
if (fetchResponse.status !== 200) {
const body = await fetchResponse.json();
throw new Error(body?.error?.message || 'Unknown error');
}
const chunks = getSSEStreamAsync(fetchResponse);
for await (const chunk of chunks) {
// const stop = chunk.stop;
if (chunk.error) {
throw new Error(chunk.error?.message || 'Unknown error');
}
const addedContent = chunk.choices[0].delta.content;
responseContent += addedContent;
const { thought, codeBlock } = splitContent(responseContent);
setThought(thought);
if (codeBlock.length > 0) {
setScript(codeBlock);
}
}
} catch (error) {
console.error(error);
alert('Failed to generate the script. Please try again.');
}
setIsGenerating(false);
};
return (
<div className="card bg-base-100 w-full shadow-xl">
<div className="card-body">
<h2 className="card-title">Step 1: Input information</h2>
<textarea
className="textarea textarea-bordered w-full h-72 p-2"
placeholder="Type your input information here (an article, a document, etc)..."
value={input}
onChange={(e) => setInput(e.target.value)}
disabled={isGenerating || busy}
></textarea>
<textarea
className="textarea textarea-bordered w-full h-24 p-2"
placeholder="Optional note (the theme, tone, etc)..."
value={note}
onChange={(e) => setNote(e.target.value)}
disabled={isGenerating || busy}
></textarea>
{thought.length > 0 && (
<>
<p>Thought process:</p>
<textarea
className="textarea textarea-bordered w-full h-24 p-2"
value={thought}
readOnly
></textarea>
</>
)}
<button
className="btn btn-primary mt-2"
onClick={generate}
disabled={isGenerating || busy}
>
{isGenerating ? (
<>
<span className="loading loading-spinner loading-sm"></span>
Generating...
</>
) : (
'Generate script'
)}
</button>
</div>
</div>
);
};
|