Allow overriding keys

fix/ai-roadmap
Kamran Ahmed 9 months ago
parent 4408fd0218
commit bf078c8b44
  1. 46
      src/components/GenerateRoadmap/GenerateRoadmap.tsx
  2. 16
      src/components/GenerateRoadmap/OpenAISettings.tsx

@ -12,10 +12,15 @@ import { generateAIRoadmapFromText } from '../../../editor/utils/roadmap-generat
import { renderFlowJSON } from '../../../editor/renderer/renderer'; import { renderFlowJSON } from '../../../editor/renderer/renderer';
import { replaceChildren } from '../../lib/dom'; import { replaceChildren } from '../../lib/dom';
import { readAIRoadmapStream } from '../../helper/read-stream'; import { readAIRoadmapStream } from '../../helper/read-stream';
import { isLoggedIn, removeAuthToken, visitAIRoadmap } from '../../lib/jwt'; import {
getOpenAPIKey,
isLoggedIn,
removeAuthToken,
visitAIRoadmap,
} from '../../lib/jwt';
import { RoadmapSearch } from './RoadmapSearch.tsx'; import { RoadmapSearch } from './RoadmapSearch.tsx';
import { Spinner } from '../ReactIcons/Spinner.tsx'; import { Spinner } from '../ReactIcons/Spinner.tsx';
import { Ban, Download, PenSquare, Save, Wand } from 'lucide-react'; import { Ban, Cog, Download, PenSquare, Save, Wand } from 'lucide-react';
import { ShareRoadmapButton } from '../ShareRoadmapButton.tsx'; import { ShareRoadmapButton } from '../ShareRoadmapButton.tsx';
import { httpGet, httpPost } from '../../lib/http.ts'; import { httpGet, httpPost } from '../../lib/http.ts';
import { pageProgressMessage } from '../../stores/page.ts'; import { pageProgressMessage } from '../../stores/page.ts';
@ -29,6 +34,7 @@ import { showLoginPopup } from '../../lib/popup.ts';
import { cn } from '../../lib/classname.ts'; import { cn } from '../../lib/classname.ts';
import { RoadmapTopicDetail } from './RoadmapTopicDetail.tsx'; import { RoadmapTopicDetail } from './RoadmapTopicDetail.tsx';
import { AIRoadmapAlert } from './AIRoadmapAlert.tsx'; import { AIRoadmapAlert } from './AIRoadmapAlert.tsx';
import { OpenAISettings } from './OpenAISettings.tsx';
export type GetAIRoadmapLimitResponse = { export type GetAIRoadmapLimitResponse = {
used: number; used: number;
@ -95,6 +101,9 @@ export function GenerateRoadmap() {
const [roadmapLimitUsed, setRoadmapLimitUsed] = useState(0); const [roadmapLimitUsed, setRoadmapLimitUsed] = useState(0);
const [roadmapTopicLimit, setRoadmapTopicLimit] = useState(0); const [roadmapTopicLimit, setRoadmapTopicLimit] = useState(0);
const [roadmapTopicLimitUsed, setRoadmapTopicLimitUsed] = useState(0); const [roadmapTopicLimitUsed, setRoadmapTopicLimitUsed] = useState(0);
const [isConfiguring, setIsConfiguring] = useState(false);
const openAPIKey = getOpenAPIKey();
const renderRoadmap = async (roadmap: string) => { const renderRoadmap = async (roadmap: string) => {
const { nodes, edges } = generateAIRoadmapFromText(roadmap); const { nodes, edges } = generateAIRoadmapFromText(roadmap);
@ -373,9 +382,19 @@ export function GenerateRoadmap() {
const pageUrl = `https://roadmap.sh/ai?id=${roadmapId}`; const pageUrl = `https://roadmap.sh/ai?id=${roadmapId}`;
const canGenerateMore = roadmapLimitUsed < roadmapLimit; const canGenerateMore = roadmapLimitUsed < roadmapLimit;
const isLoggedInUser = isLoggedIn();
return ( return (
<> <>
{isConfiguring && (
<OpenAISettings
onClose={() => {
setIsConfiguring(false);
loadAIRoadmapLimit().finally(() => null);
}}
/>
)}
{selectedNode && currentRoadmap && !isLoading && ( {selectedNode && currentRoadmap && !isLoading && (
<RoadmapTopicDetail <RoadmapTopicDetail
nodeId={selectedNode.nodeId} nodeId={selectedNode.nodeId}
@ -421,7 +440,7 @@ export function GenerateRoadmap() {
</span>{' '} </span>{' '}
roadmaps generated. roadmaps generated.
</span> </span>
{!isLoggedIn() && ( {!isLoggedInUser && (
<button <button
className="rounded-xl border border-current px-1.5 py-0.5 text-left text-sm font-medium text-blue-500 sm:text-center" className="rounded-xl border border-current px-1.5 py-0.5 text-left text-sm font-medium text-blue-500 sm:text-center"
onClick={showLoginPopup} onClick={showLoginPopup}
@ -433,6 +452,27 @@ export function GenerateRoadmap() {
or <span className="font-semibold">logging in</span> or <span className="font-semibold">logging in</span>
</button> </button>
)} )}
{isLoggedInUser && !openAPIKey && (
<button
onClick={() => setIsConfiguring(true)}
className="rounded-xl border border-current px-2 py-0.5 text-sm text-blue-500 transition-colors hover:bg-blue-400 hover:text-white"
>
By-pass all limits by{' '}
<span className="font-semibold">
adding your own OpenAI API key
</span>
</button>
)}
{isLoggedInUser && openAPIKey && (
<button
onClick={() => setIsConfiguring(true)}
className="flex flex-row items-center gap-1 rounded-xl border border-current px-2 py-0.5 text-sm text-blue-500 transition-colors hover:bg-blue-400 hover:text-white"
>
<Cog size={15} />
Configure OpenAI API key
</button>
)}
</div> </div>
<form <form
onSubmit={handleSubmit} onSubmit={handleSubmit}

@ -16,6 +16,8 @@ type OpenAISettingsProps = {
export function OpenAISettings(props: OpenAISettingsProps) { export function OpenAISettings(props: OpenAISettingsProps) {
const { onClose } = props; const { onClose } = props;
const [defaultOpenAIKey, setDefaultOpenAIKey] = useState('');
const [hasError, setHasError] = useState(false); const [hasError, setHasError] = useState(false);
const [openaiApiKey, setOpenaiApiKey] = useState(''); const [openaiApiKey, setOpenaiApiKey] = useState('');
const toast = useToast(); const toast = useToast();
@ -23,6 +25,7 @@ export function OpenAISettings(props: OpenAISettingsProps) {
useEffect(() => { useEffect(() => {
const apiKey = getOpenAPIKey(); const apiKey = getOpenAPIKey();
setOpenaiApiKey(apiKey || ''); setOpenaiApiKey(apiKey || '');
setDefaultOpenAIKey(apiKey || '');
}, []); }, []);
return ( return (
@ -112,6 +115,19 @@ export function OpenAISettings(props: OpenAISettingsProps) {
> >
Save Save
</button> </button>
{defaultOpenAIKey && (
<button
type="button"
onClick={() => {
deleteOpenAPIKey();
onClose();
toast.success('OpenAI API key removed');
}}
className="mt-1 w-full rounded-md bg-red-500 px-4 py-2 text-white transition-colors hover:bg-black hover:bg-red-700"
>
Reset to Default Key
</button>
)}
</form> </form>
</div> </div>
</div> </div>

Loading…
Cancel
Save