diff --git a/ui/app/api/modify-frontend-component/push-stack-to-github.ts b/ui/app/api/modify-frontend-component/push-stack-to-github.ts deleted file mode 100644 index 8a7fd5df..00000000 --- a/ui/app/api/modify-frontend-component/push-stack-to-github.ts +++ /dev/null @@ -1,166 +0,0 @@ -// import { stackDB } from '@/app/stacks/stack-db'; -import { Octokit } from '@octokit/rest'; -import axios from 'axios'; - -const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }); -const owner = 'stackwiseai'; -const repo = 'stackwise'; -const vercelToken = process.env.VERCEL_TOKEN; -const teamId = process.env.TEAM_ID; -const repoId = process.env.REPO_ID; -const randomString = generateRandomString(10); -const sourceBranch = process.env.VERCEL_GIT_COMMIT_REF ?? ''; // or 'master', depending on your repository -export async function pushStackToGithub( - fileContent: any, - path, - message, - isBinary = false, -) { - const branch = sourceBranch; - - const gitDiffUrl = await pushToBranch( - fileContent, - branch, - path, - message, - isBinary, - ); - console.log('gitDiffUrl', gitDiffUrl); - // const vercelLink = await deployToVercel(branch); - const vercelLink = ''; - const responseJson = { gitDiffUrl, vercelLink }; - return responseJson; -} - -async function pushToBranch(newContent, branch, path, message, isBinary) { - try { - let parentSha; - const { data: sourceBranchData } = await octokit.repos.getBranch({ - owner, - repo, - branch: sourceBranch, - }); - parentSha = sourceBranchData.commit.sha; - - const { data: commitData } = await octokit.git.getCommit({ - owner, - repo, - commit_sha: parentSha, - }); - const treeSha = commitData.tree.sha; - - const { data: treeData } = await octokit.git.createTree({ - owner, - repo, - tree: [ - isBinary - ? { - path, - mode: '100644', // blob (file) - type: 'blob', - sha: newContent, - } - : { - path, - mode: '100644', // blob (file) - type: 'blob', - content: newContent, - }, - ], - base_tree: treeSha, - }); - - // Create a new commit with the new tree and the parent commit - const { data: newCommitData } = await octokit.git.createCommit({ - owner, - repo, - message, - tree: treeData.sha, - parents: [parentSha], - }); - - console.log('Created commit:', newCommitData.sha); - - // Update the branch reference to point to the new commit - await octokit.git.updateRef({ - owner, - repo, - ref: `heads/${branch}`, - sha: newCommitData.sha, - }); - - console.log('Successfully pushed to branch:', branch); - const gitDiffLink = `https://github.com/${owner}/${repo}/compare/${sourceBranch}...${branch}`; - console.log('gitDiffLink', gitDiffLink); - return gitDiffLink; - } catch (error) { - console.error('Error pushing to branch:', error); - } -} - -function generateRandomString(length: number): string { - const characters = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - let result = ''; - const charactersLength = characters.length; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} - -async function deployToVercel(branch) { - const apiEndpoint = 'https://api.vercel.com/v9/now/deployments'; - - let config = { - method: 'post', - url: apiEndpoint + (teamId ? `?teamId=${teamId}` : ''), - headers: { - Authorization: `Bearer ${vercelToken}`, - 'Content-Type': 'application/json', - }, - data: { - name: repo, - gitSource: { - type: 'github', - ref: branch, - repo: `${owner}/${repo}`, - repoId: repoId, - }, - }, - }; - - try { - const response = await axios(config); - return `https://${response.data.alias[0]}`; - } catch (error) { - if (error.response) { - // The request was made and the server responded with a status code - // that falls out of the range of 2xx - console.error('Error Data:', error.response.data); - console.error('Error Status:', error.response.status); - console.error('Error Headers:', error.response.headers); - } else if (error.request) { - // The request was made but no response was received - console.error('Error Request:', error.request); - } else { - // Something happened in setting up the request that triggered an Error - console.error('Error Message:', error.message); - } - console.error('Error Config:', error.config); - } -} - -function sortJSONKeys(data: Record): Record { - return Object.keys(data) - .sort() - .reduce((obj: Record, key: string) => { - obj[key] = data[key]; - return obj; - }, {}); -} - -function formatSortedJSON(data: Record): string { - const sortedData = sortJSONKeys(data); - return `export const stackDB = ${JSON.stringify(sortedData, null, 2)};`; -} diff --git a/ui/app/api/modify-frontend-component/route.ts b/ui/app/api/modify-frontend-component/route.ts deleted file mode 100644 index e5298d6c..00000000 --- a/ui/app/api/modify-frontend-component/route.ts +++ /dev/null @@ -1,23 +0,0 @@ -export async function POST(req) { - // const json = await req.json(); - // console.log(json); - // const { fileContent, stackName } = json; - // const generatedUuid = uuidv4(); - // const randomChars = generatedUuid.replace(/-/g, "").substring(0, 7); - // const actualStackName = `${stackName}-${randomChars}`; - // const path = `ui/app/components/stacks/${actualStackName}.tsx`; - // const message = `Building ${actualStackName}`; - // const extractedContent = extractTsxOrJsx(fileContent); - // console.log(extractedContent); - // if (!extractedContent) { - // throw new Error("No tsx code found in the response"); - // } - // const responseJson = await pushStackToGithub(extractedContent, path, message); - // return Response.json(responseJson); -} - -function extractTsxOrJsx(inputString) { - const regex = /```(tsx|jsx|javascript|js|ts|typescript)\s*([\s\S]*?)\s*```/; - const match = inputString.match(regex); - return match ? match[2].trim() : inputString; -} diff --git a/ui/app/actions.ts b/ui/app/api/stacks/v1/actions.ts similarity index 100% rename from ui/app/actions.ts rename to ui/app/api/stacks/v1/actions.ts diff --git a/ui/app/api/basic-openai/route.ts b/ui/app/api/stacks/v1/basic-openai/route.ts similarity index 100% rename from ui/app/api/basic-openai/route.ts rename to ui/app/api/stacks/v1/basic-openai/route.ts diff --git a/ui/app/api/boilerplate-basic/route.ts b/ui/app/api/stacks/v1/boilerplate-basic/route.ts similarity index 100% rename from ui/app/api/boilerplate-basic/route.ts rename to ui/app/api/stacks/v1/boilerplate-basic/route.ts diff --git a/ui/app/api/chat-gemini-streaming-langchain/route.ts b/ui/app/api/stacks/v1/chat-gemini-streaming-langchain/route.ts similarity index 100% rename from ui/app/api/chat-gemini-streaming-langchain/route.ts rename to ui/app/api/stacks/v1/chat-gemini-streaming-langchain/route.ts diff --git a/ui/app/api/chat-with-gemini-langchain/route.ts b/ui/app/api/stacks/v1/chat-with-gemini-langchain/route.ts similarity index 100% rename from ui/app/api/chat-with-gemini-langchain/route.ts rename to ui/app/api/stacks/v1/chat-with-gemini-langchain/route.ts diff --git a/ui/app/api/chat-with-gemini-streaming/route.ts b/ui/app/api/stacks/v1/chat-with-gemini-streaming/route.ts similarity index 100% rename from ui/app/api/chat-with-gemini-streaming/route.ts rename to ui/app/api/stacks/v1/chat-with-gemini-streaming/route.ts diff --git a/ui/app/api/chat-with-gemini/route.ts b/ui/app/api/stacks/v1/chat-with-gemini/route.ts similarity index 100% rename from ui/app/api/chat-with-gemini/route.ts rename to ui/app/api/stacks/v1/chat-with-gemini/route.ts diff --git a/ui/app/api/chat-with-openai-streaming-helicone/route.ts b/ui/app/api/stacks/v1/chat-with-openai-streaming-helicone/route.ts similarity index 100% rename from ui/app/api/chat-with-openai-streaming-helicone/route.ts rename to ui/app/api/stacks/v1/chat-with-openai-streaming-helicone/route.ts diff --git a/ui/app/api/chat-with-openai-streaming-langchain/route.ts b/ui/app/api/stacks/v1/chat-with-openai-streaming-langchain/route.ts similarity index 100% rename from ui/app/api/chat-with-openai-streaming-langchain/route.ts rename to ui/app/api/stacks/v1/chat-with-openai-streaming-langchain/route.ts diff --git a/ui/app/api/chat-with-openai-streaming/route.ts b/ui/app/api/stacks/v1/chat-with-openai-streaming/route.ts similarity index 100% rename from ui/app/api/chat-with-openai-streaming/route.ts rename to ui/app/api/stacks/v1/chat-with-openai-streaming/route.ts diff --git a/ui/app/api/cover-image-and-subtitle/route.ts b/ui/app/api/stacks/v1/cover-image-and-subtitle/route.ts similarity index 100% rename from ui/app/api/cover-image-and-subtitle/route.ts rename to ui/app/api/stacks/v1/cover-image-and-subtitle/route.ts diff --git a/ui/app/api/create-stack-boilerplate/create-stack.ts b/ui/app/api/stacks/v1/create-stack-boilerplate/create-stack.ts similarity index 67% rename from ui/app/api/create-stack-boilerplate/create-stack.ts rename to ui/app/api/stacks/v1/create-stack-boilerplate/create-stack.ts index 2b5188b9..84db6282 100644 --- a/ui/app/api/create-stack-boilerplate/create-stack.ts +++ b/ui/app/api/stacks/v1/create-stack-boilerplate/create-stack.ts @@ -1,5 +1,5 @@ +import { getSupabaseClient } from '@/app/components/stacks/utils/stack-db'; -import { getSupabaseClient } from '@/app/stacks/stack-db'; import getFileFromGithub from './get-file-from-github'; import pushMultipleFilesToBranch from './push-multiple-files-to-branch'; @@ -8,32 +8,31 @@ export default async function createStack(data, token) { .replace(/([a-z])([A-Z])/g, '$1-$2') .replace(/\s+/g, '-') .toLowerCase(); - + const supabase = await getSupabaseClient(); const stackInfo = { name: data.name, id: stackId, description: data.description, tags: ['draft'], - } - const { data: insertedData, error } = await supabase + }; + const { data: insertedData, error } = await supabase .from('stack') - .insert([ - stackInfo - ]) + .insert([stackInfo]) .single(); - if (error) { - if (error.message.includes('duplicate key ')) { - throw new Error('This app already exists.'); - } - throw error; + if (error) { + if (error.message.includes('duplicate key ')) { + throw new Error('This app already exists.'); } - + throw error; + } + // creating api key - let path = `ui/app/components/stacks/${stackInfo.id}.tsx`; + let path = `ui/app/components/stacks/v1/${stackInfo.id}.tsx`; let message = `Frontend For ${stackInfo.id} created`; let response = await getFileFromGithub( - 'ui/public/stacks/boilerplate-basic.tsx', token + 'ui/public/stacks/v1/boilerplate-basic.tsx', + token, ); await new Promise((resolve) => setTimeout(resolve, 500)); @@ -45,10 +44,11 @@ export default async function createStack(data, token) { }, ]; - path = `ui/app/api/${stackInfo.id}/route.ts`; + path = `ui/app/api/stacks/v1/${stackInfo.id}/route.ts`; message = `Backend For ${stackInfo.id} created`; response = await getFileFromGithub( - 'ui/public/stacks/boilerplate-basic/route.ts', token + 'ui/public/stacks/v1/boilerplate-basic/route.ts', + token, ); await new Promise((resolve) => setTimeout(resolve, 500)); @@ -62,7 +62,8 @@ export default async function createStack(data, token) { message = `Preview For ${stackInfo.id} created`; response = await getFileFromGithub( - 'ui/public/stack-pictures/boilerplate-basic.png', token + 'ui/public/stack-pictures/boilerplate-basic.png', + token, ); await new Promise((resolve) => setTimeout(resolve, 500)); @@ -73,6 +74,10 @@ export default async function createStack(data, token) { }); // const sourceBranch = process.env.VERCEL_GIT_COMMIT_REF ?? ''; // or 'master', depending on your repository - const prLink = await pushMultipleFilesToBranch(filesArray, stackInfo.id, token); + const prLink = await pushMultipleFilesToBranch( + filesArray, + stackInfo.id, + token, + ); return prLink; } diff --git a/ui/app/api/create-stack-boilerplate/get-file-from-github.ts b/ui/app/api/stacks/v1/create-stack-boilerplate/get-file-from-github.ts similarity index 100% rename from ui/app/api/create-stack-boilerplate/get-file-from-github.ts rename to ui/app/api/stacks/v1/create-stack-boilerplate/get-file-from-github.ts diff --git a/ui/app/api/create-stack-boilerplate/push-multiple-files-to-branch.ts b/ui/app/api/stacks/v1/create-stack-boilerplate/push-multiple-files-to-branch.ts similarity index 100% rename from ui/app/api/create-stack-boilerplate/push-multiple-files-to-branch.ts rename to ui/app/api/stacks/v1/create-stack-boilerplate/push-multiple-files-to-branch.ts diff --git a/ui/app/api/create-stack-boilerplate/route.ts b/ui/app/api/stacks/v1/create-stack-boilerplate/route.ts similarity index 100% rename from ui/app/api/create-stack-boilerplate/route.ts rename to ui/app/api/stacks/v1/create-stack-boilerplate/route.ts diff --git a/ui/app/api/elevenlabs-tts/route.ts b/ui/app/api/stacks/v1/elevenlabs-tts/route.ts similarity index 100% rename from ui/app/api/elevenlabs-tts/route.ts rename to ui/app/api/stacks/v1/elevenlabs-tts/route.ts diff --git a/ui/app/api/get-image-description-openai/route.ts b/ui/app/api/stacks/v1/get-image-description-openai/route.ts similarity index 100% rename from ui/app/api/get-image-description-openai/route.ts rename to ui/app/api/stacks/v1/get-image-description-openai/route.ts diff --git a/ui/app/api/getAWSPresignedUrl/route.ts b/ui/app/api/stacks/v1/getAWSPresignedUrl/route.ts similarity index 100% rename from ui/app/api/getAWSPresignedUrl/route.ts rename to ui/app/api/stacks/v1/getAWSPresignedUrl/route.ts diff --git a/ui/app/api/image-sharpener/route.ts b/ui/app/api/stacks/v1/image-sharpener/route.ts similarity index 100% rename from ui/app/api/image-sharpener/route.ts rename to ui/app/api/stacks/v1/image-sharpener/route.ts diff --git a/ui/app/api/image-to-music/route.ts b/ui/app/api/stacks/v1/image-to-music/route.ts similarity index 100% rename from ui/app/api/image-to-music/route.ts rename to ui/app/api/stacks/v1/image-to-music/route.ts diff --git a/ui/app/api/rag-pdf-with-langchain/route.ts b/ui/app/api/stacks/v1/rag-pdf-with-langchain/route.ts similarity index 100% rename from ui/app/api/rag-pdf-with-langchain/route.ts rename to ui/app/api/stacks/v1/rag-pdf-with-langchain/route.ts diff --git a/ui/app/api/stable-video-diffusion/route.ts b/ui/app/api/stacks/v1/stable-video-diffusion/route.ts similarity index 100% rename from ui/app/api/stable-video-diffusion/route.ts rename to ui/app/api/stacks/v1/stable-video-diffusion/route.ts diff --git a/ui/app/api/text-to-qr/route.ts b/ui/app/api/stacks/v1/text-to-qr/route.ts similarity index 100% rename from ui/app/api/text-to-qr/route.ts rename to ui/app/api/stacks/v1/text-to-qr/route.ts diff --git a/ui/app/api/use-openai-assistant/route.ts b/ui/app/api/stacks/v1/use-openai-assistant/route.ts similarity index 100% rename from ui/app/api/use-openai-assistant/route.ts rename to ui/app/api/stacks/v1/use-openai-assistant/route.ts diff --git a/ui/app/api/stackwise-onboarding/route.ts b/ui/app/api/stackwise-onboarding/route.ts deleted file mode 100644 index d063e77a..00000000 --- a/ui/app/api/stackwise-onboarding/route.ts +++ /dev/null @@ -1,6 +0,0 @@ -export async function POST(req: Request) { - const { input } = await req.json(); - return new Response( - JSON.stringify({ output: `You sent this message to the server: ${input}` }), - ); -} diff --git a/ui/app/api/suggest-frontend-component/route.ts b/ui/app/api/suggest-frontend-component/route.ts deleted file mode 100644 index 64da8366..00000000 --- a/ui/app/api/suggest-frontend-component/route.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { OpenAIStream, StreamingTextResponse } from 'ai'; -import OpenAI from 'openai'; - -const openAIAPIKey = process.env.OPENAI_API_KEY; -const heliconeAPIKey = process.env.HELICONE_API_KEY; -const owner = 'stackwiseai'; -const repo = 'stackwise'; -const sourceBranch = process.env.VERCEL_GIT_COMMIT_REF ?? ''; -const openai = new OpenAI({ - apiKey: openAIAPIKey, - baseURL: 'https://oai.hconeai.com/v1', - defaultHeaders: { - 'Helicone-Auth': `Bearer ${heliconeAPIKey}`, - 'Helicone-Cache-Enabled': 'true', - }, -}); - -export const runtime = 'edge'; - -export async function POST(req: Request) { - // if (req.method !== 'POST') { - // res.setHeader('Allow', ['POST']); - // res.status(405).end(`Method ${req.method} Not Allowed`); - // } - const bodyText = await req.text(); - console.log('bodyText', bodyText); - const body = JSON.parse(bodyText); - - console.log('brief', body.brief); - - console.log('test'); - - const codeToChange = await getCurrentCode(); - - console.log(codeToChange, bodyText); - const systemInstructions = `You are a developer focused on writing on only one single file. -You always return a single snippet of typescript code and it's always the full code, even if it's repetitive and long. - -Please note that the code should be fully functional. No placeholders. -Always stay in the same page, you're not allowed to switch page. -please -Note You are using nextjs 14. Never remove the "use client"; on top of the file`; - - const content = `This is the app I am working with: -${codeToChange} -This is what I would like to change: -${body.brief} -Please could you rewrite entirely this file, following the system instructions ? -`; - const response = await openai.chat.completions.create({ - model: 'gpt-4-1106-preview', - messages: [ - { - role: 'system', - content: systemInstructions, - }, - { role: 'user', content: content }, - ], - stream: true, - temperature: 0, - }); - const stream = OpenAIStream(response); - - return new StreamingTextResponse(stream); -} - -async function getCurrentCode() { - try { - const response = await fetch( - `https://api.github.com/repos/${owner}/${repo}/contents/web/src/app/Home.tsx?ref=${sourceBranch}`, - { - headers: { - Authorization: `token ${process.env.GITHUB_TOKEN}`, - }, - }, - ); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data = await response.json(); - const fileContentBase64 = data.content; - console.log(fileContentBase64); - - const fileContent = Buffer.from(fileContentBase64, 'base64').toString( - 'utf-8', - ); - console.log(fileContent); - - return fileContent; - } catch (error) { - console.error(error); - } -} - -async function getChangedCode(codeToChange, brief) {} diff --git a/ui/app/components/clipboard.tsx b/ui/app/components/shared/clipboard.tsx similarity index 100% rename from ui/app/components/clipboard.tsx rename to ui/app/components/shared/clipboard.tsx diff --git a/ui/app/components/stacks/basic-boilerplate.tsx b/ui/app/components/stacks/basic-boilerplate.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/app/components/stacks/basic-boilerplate.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/app/components/stacks/cdscds.tsx b/ui/app/components/stacks/cdscds.tsx deleted file mode 100644 index 5267cfc6..00000000 --- a/ui/app/components/stacks/cdscds.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ messages: inputValue }), - }); - const data = await response.json(); - setOutput(data.output); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/app/components/stacks/get-roasted.tsx b/ui/app/components/stacks/get-roasted.tsx deleted file mode 100644 index 81d6961d..00000000 --- a/ui/app/components/stacks/get-roasted.tsx +++ /dev/null @@ -1,78 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { useChat } from 'ai/react'; -import { IoSend } from 'react-icons/io5'; - -export default function Chat() { - const [image, setImage] = useState( - 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Field_sparrow_in_CP_%2841484%29_%28cropped%29.jpg/733px-Field_sparrow_in_CP_%2841484%29_%28cropped%29.jpg', - ); - - const { messages, input, handleInputChange, handleSubmit } = useChat({ - api: '/api/getImageDescriptionOpenAI', - }); - - const handleImageChange = (e) => { - if (e.target.files && e.target.files[0]) { - const file = e.target.files[0]; - const reader = new FileReader(); - reader.onloadend = () => { - if (typeof reader.result === 'string') { - setImage(reader.result); - } else { - // Handle the case where the result is not a string - console.error('File could not be converted to base64 string'); - } - }; - reader.readAsDataURL(file); - } - }; - - return ( -
-
{ - handleSubmit(e, { - data: { - imageUrl: image, - }, - }); - }} - className="flex w-3/4 flex-col items-center space-y-4 md:w-1/2 lg:w-2/5" - > - - {image && Preview} -
- - -
-
-
- {messages.length > 0 - ? messages.map((m) => ( -
- {m.role === 'user' ? 'User: ' : 'AI: '} - {m.content} -
- )) - : null} -
-
- ); -} diff --git a/ui/app/components/stacks/hello-world.tsx b/ui/app/components/stacks/hello-world.tsx deleted file mode 100644 index 23e710c1..00000000 --- a/ui/app/components/stacks/hello-world.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -interface HelloWorldProps { - // Define any props here if needed -} - -const HelloWorld: React.FC = (props) => { - return
Hello World!
; -}; - -export default HelloWorld; diff --git a/ui/app/components/stacks/load-ts-react-component.tsx b/ui/app/components/stacks/load-ts-react-component.tsx deleted file mode 100644 index 23e710c1..00000000 --- a/ui/app/components/stacks/load-ts-react-component.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -interface HelloWorldProps { - // Define any props here if needed -} - -const HelloWorld: React.FC = (props) => { - return
Hello World!
; -}; - -export default HelloWorld; diff --git a/ui/app/components/stacks/minimalist-agent-protocol.tsx b/ui/app/components/stacks/minimalist-agent-protocol.tsx deleted file mode 100644 index ccb5c11a..00000000 --- a/ui/app/components/stacks/minimalist-agent-protocol.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; - -export const Stack = () => { - const [inputValue, setInputValue] = useState(''); - const [generatedFileContents, setGeneratedFileContents] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setGeneratedFileContents(''); - setLoading(true); - - try { - const response = await fetch('/api/chat-with-openai-streaming', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ messages: inputValue }), - }); - const data = await response.body; - - if (!data) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const reader = data.getReader(); - const decoder = new TextDecoder(); - let done = false; - let fullContent = ''; - - while (!done) { - const { value, done: doneReading } = await reader.read(); - done = doneReading; - const chunkValue = decoder.decode(value, { stream: !done }); - setGeneratedFileContents((prev) => prev + chunkValue); - setLoading(false); - fullContent += chunkValue; - } - } catch (error) { - console.error('Error during fetch:', error); - } finally { - setInputValue(''); // Clear the input field - setLoading(false); - } - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : generatedFileContents ? ( - generatedFileContents - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default Stack; diff --git a/ui/app/components/stacks/stack-example.tsx b/ui/app/components/stacks/stack-example.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/app/components/stacks/stack-example.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/app/components/stacks/stackwise-onboarding.tsx b/ui/app/components/stacks/stackwise-onboarding.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/app/components/stacks/stackwise-onboarding.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/app/components/stacks/test-action-4.tsx b/ui/app/components/stacks/test-action-4.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/app/components/stacks/test-boilerplate.tsx b/ui/app/components/stacks/test-boilerplate.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/app/components/stacks/test-create-stack.tsx b/ui/app/components/stacks/test-create-stack.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/app/components/stacks/test-create-stack.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/app/components/stacks/test-stack-123.tsx b/ui/app/components/stacks/test-stack-123.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/app/components/stacks/test-stack-123.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/app/components/stacks/test-stack-creation-12324.tsx b/ui/app/components/stacks/test-stack-creation-12324.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/app/components/stacks/test-stack-creation-12324.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/app/components/stacks/test-supabase-stacks-1.tsx b/ui/app/components/stacks/test-supabase-stacks-1.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/app/components/stacks/test-supabase-stacks-1.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/app/components/stacks/test-supabase-stacks.tsx b/ui/app/components/stacks/test-supabase-stacks.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/app/components/stacks/test-supabase-stacks.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/app/components/ContactButton.tsx b/ui/app/components/stacks/utils/ContactButton.tsx similarity index 100% rename from ui/app/components/ContactButton.tsx rename to ui/app/components/stacks/utils/ContactButton.tsx diff --git a/ui/app/components/MailchimpSubscribe.tsx b/ui/app/components/stacks/utils/MailchimpSubscribe.tsx similarity index 93% rename from ui/app/components/MailchimpSubscribe.tsx rename to ui/app/components/stacks/utils/MailchimpSubscribe.tsx index 8f40cca4..b84a2c18 100644 --- a/ui/app/components/MailchimpSubscribe.tsx +++ b/ui/app/components/stacks/utils/MailchimpSubscribe.tsx @@ -4,8 +4,8 @@ import { useFormState, useFormStatus } from 'react-dom'; import { IoSend } from 'react-icons/io5'; import tw from 'tailwind-styled-components'; -import { subscribeEmail } from '../actions'; -import { Form } from './input-with-button'; +import { subscribeEmail } from '../../../api/stacks/v1/actions'; +import { Form } from '../v1/creation/input-with-button'; const glowingShadowStyle = { boxShadow: `0 0 10px rgba(0, 0, 0, 0.1), diff --git a/ui/app/components/search-stacks.tsx b/ui/app/components/stacks/utils/search-stacks.tsx similarity index 100% rename from ui/app/components/search-stacks.tsx rename to ui/app/components/stacks/utils/search-stacks.tsx diff --git a/ui/app/stacks/signIn.tsx b/ui/app/components/stacks/utils/signIn.tsx similarity index 100% rename from ui/app/stacks/signIn.tsx rename to ui/app/components/stacks/utils/signIn.tsx diff --git a/ui/app/stacks/signOut.tsx b/ui/app/components/stacks/utils/signOut.tsx similarity index 100% rename from ui/app/stacks/signOut.tsx rename to ui/app/components/stacks/utils/signOut.tsx diff --git a/ui/app/stacks/stack-db.ts b/ui/app/components/stacks/utils/stack-db.ts similarity index 100% rename from ui/app/stacks/stack-db.ts rename to ui/app/components/stacks/utils/stack-db.ts diff --git a/ui/app/components/stacks/boilerplate-basic.tsx b/ui/app/components/stacks/v1/boilerplate-basic.tsx similarity index 94% rename from ui/app/components/stacks/boilerplate-basic.tsx rename to ui/app/components/stacks/v1/boilerplate-basic.tsx index 2fcfd8c3..7de0fc83 100644 --- a/ui/app/components/stacks/boilerplate-basic.tsx +++ b/ui/app/components/stacks/v1/boilerplate-basic.tsx @@ -14,7 +14,7 @@ export const ChatWithOpenAIStreaming = () => { setOutput(''); setLoading(true); - const response = await fetch('/api/boilerplate-basic', { + const response = await fetch('/api/stacks/v1/boilerplate-basic', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -53,7 +53,7 @@ export const ChatWithOpenAIStreaming = () => { -
+
{loading ? ( Generating... ) : output ? ( diff --git a/ui/public/stacks/chat-gemini-streaming-langchain.tsx b/ui/app/components/stacks/v1/chat-gemini-streaming-langchain.tsx similarity index 88% rename from ui/public/stacks/chat-gemini-streaming-langchain.tsx rename to ui/app/components/stacks/v1/chat-gemini-streaming-langchain.tsx index a47b0254..91794993 100644 --- a/ui/public/stacks/chat-gemini-streaming-langchain.tsx +++ b/ui/app/components/stacks/v1/chat-gemini-streaming-langchain.tsx @@ -15,13 +15,16 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-gemini-streaming-langchain', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-gemini-streaming-langchain', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.body; if (!data) { @@ -75,7 +78,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/public/stacks/chat-with-gemini-langchain.tsx b/ui/app/components/stacks/v1/chat-with-gemini-langchain.tsx similarity index 87% rename from ui/public/stacks/chat-with-gemini-langchain.tsx rename to ui/app/components/stacks/v1/chat-with-gemini-langchain.tsx index 10d5f8c1..bdada6d0 100644 --- a/ui/public/stacks/chat-with-gemini-langchain.tsx +++ b/ui/app/components/stacks/v1/chat-with-gemini-langchain.tsx @@ -15,13 +15,16 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-with-gemini-langchain', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-with-gemini-langchain', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.json(); console.log('data', data); if (!data) { @@ -62,7 +65,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/app/components/stacks/chat-with-gemini-streaming.tsx b/ui/app/components/stacks/v1/chat-with-gemini-streaming.tsx similarity index 88% rename from ui/app/components/stacks/chat-with-gemini-streaming.tsx rename to ui/app/components/stacks/v1/chat-with-gemini-streaming.tsx index 8374f1f1..15b852d5 100644 --- a/ui/app/components/stacks/chat-with-gemini-streaming.tsx +++ b/ui/app/components/stacks/v1/chat-with-gemini-streaming.tsx @@ -15,13 +15,16 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-with-gemini-streaming', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-with-gemini-streaming', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.body; if (!data) { @@ -75,7 +78,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/public/stacks/chat-with-gemini.tsx b/ui/app/components/stacks/v1/chat-with-gemini.tsx similarity index 95% rename from ui/public/stacks/chat-with-gemini.tsx rename to ui/app/components/stacks/v1/chat-with-gemini.tsx index ae92a83e..a41faaf7 100644 --- a/ui/public/stacks/chat-with-gemini.tsx +++ b/ui/app/components/stacks/v1/chat-with-gemini.tsx @@ -14,7 +14,7 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-with-gemini', { + const response = await fetch('/api/stacks/v1/chat-with-gemini', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -74,7 +74,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/app/components/stacks/chat-with-openai-streaming-helicone.tsx b/ui/app/components/stacks/v1/chat-with-openai-streaming-helicone.tsx similarity index 88% rename from ui/app/components/stacks/chat-with-openai-streaming-helicone.tsx rename to ui/app/components/stacks/v1/chat-with-openai-streaming-helicone.tsx index 22e1261b..04afd2be 100644 --- a/ui/app/components/stacks/chat-with-openai-streaming-helicone.tsx +++ b/ui/app/components/stacks/v1/chat-with-openai-streaming-helicone.tsx @@ -14,13 +14,16 @@ export const ChatWithOpenAIStreamingHelicone = () => { setLoading(true); try { - const response = await fetch('/api/chat-openai-streaming-helicone', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-openai-streaming-helicone', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.body; if (!data) { @@ -74,7 +77,7 @@ export const ChatWithOpenAIStreamingHelicone = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/app/components/stacks/chat-with-openai-streaming-langchain.tsx b/ui/app/components/stacks/v1/chat-with-openai-streaming-langchain.tsx similarity index 100% rename from ui/app/components/stacks/chat-with-openai-streaming-langchain.tsx rename to ui/app/components/stacks/v1/chat-with-openai-streaming-langchain.tsx diff --git a/ui/app/components/stacks/chat-with-openai-streaming.tsx b/ui/app/components/stacks/v1/chat-with-openai-streaming.tsx similarity index 88% rename from ui/app/components/stacks/chat-with-openai-streaming.tsx rename to ui/app/components/stacks/v1/chat-with-openai-streaming.tsx index fd13f6ab..e95d4358 100644 --- a/ui/app/components/stacks/chat-with-openai-streaming.tsx +++ b/ui/app/components/stacks/v1/chat-with-openai-streaming.tsx @@ -14,13 +14,16 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-with-openai-streaming', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-with-openai-streaming', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.body; if (!data) { @@ -74,7 +77,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/app/components/stacks/cover-image-and-subtitle.tsx b/ui/app/components/stacks/v1/cover-image-and-subtitle.tsx similarity index 97% rename from ui/app/components/stacks/cover-image-and-subtitle.tsx rename to ui/app/components/stacks/v1/cover-image-and-subtitle.tsx index a489d148..d40d7893 100644 --- a/ui/app/components/stacks/cover-image-and-subtitle.tsx +++ b/ui/app/components/stacks/v1/cover-image-and-subtitle.tsx @@ -23,7 +23,7 @@ export const GenerateImageAndSubtitle = () => { const file = e.target.files[0]; try { // Fetch the presigned URL - const response = await fetch('/api/getAWSPresignedUrl', { + const response = await fetch('/api/stacks/v1/getAWSPresignedUrl', { method: 'POST', body: JSON.stringify({ fileName: file.name, @@ -71,7 +71,7 @@ export const GenerateImageAndSubtitle = () => { setLoading(true); if (!video) return; - const response = await fetch('/api/cover-image-and-subtitle', { + const response = await fetch('/api/stacks/v1/cover-image-and-subtitle', { method: 'POST', body: JSON.stringify({ fileName: video.name }), }); diff --git a/ui/app/components/stacks/create-ai-canvas.tsx b/ui/app/components/stacks/v1/create-ai-canvas.tsx similarity index 100% rename from ui/app/components/stacks/create-ai-canvas.tsx rename to ui/app/components/stacks/v1/create-ai-canvas.tsx diff --git a/ui/public/stacks/create-stack-boilerplate.tsx b/ui/app/components/stacks/v1/create-stack-boilerplate.tsx similarity index 68% rename from ui/public/stacks/create-stack-boilerplate.tsx rename to ui/app/components/stacks/v1/create-stack-boilerplate.tsx index 52f3cb09..cfc20225 100644 --- a/ui/public/stacks/create-stack-boilerplate.tsx +++ b/ui/app/components/stacks/v1/create-stack-boilerplate.tsx @@ -1,38 +1,41 @@ -"use client" -import SignIn from '@/app/stacks/signIn'; -import { supabaseClient } from '@/app/stacks/stack-db'; -import Link from 'next/link'; +'use client'; + import { useEffect, useState } from 'react'; +import Link from 'next/link'; +import SignIn from '@/app/components/stacks/utils/signIn'; +import { supabaseClient } from '@/app/components/stacks/utils/stack-db'; export const BasicForm = () => { const [formData, setFormData] = useState({ - name: 'My New App', + name: 'My New App', }); const [formErrors, setFormErrors] = useState({ id: '' }); const [Message, setMessage] = useState(''); const [isUserSignedIn, setIsUserSignedIn] = useState(false); - const [username, setUsername] = useState(""); - const [token, setToken] = useState(""); - const [pullRequestUrl, setPullRequestUrl] = useState(""); + const [username, setUsername] = useState(''); + const [token, setToken] = useState(''); + const [pullRequestUrl, setPullRequestUrl] = useState(''); const [isLoading, setIsLoading] = useState(false); useEffect(() => { // Check if user is signed in async function checkUser() { try { - const session = await supabaseClient.auth.getSession() - const token = session?.data?.session?.provider_token + const session = await supabaseClient.auth.getSession(); + const token = session?.data?.session?.provider_token; if (token) { setIsUserSignedIn(true); - setUsername(session?.data?.session?.user.user_metadata.preferred_username) - setToken(token) + setUsername( + session?.data?.session?.user.user_metadata.preferred_username, + ); + setToken(token); } } catch { - console.log("Error getting user") + console.log('Error getting user'); } } - checkUser() + checkUser(); }, []); // const { getToken } = useAuth(); @@ -58,7 +61,7 @@ export const BasicForm = () => { event.preventDefault(); try { - const response = await fetch('/api/create-stack-boilerplate', { + const response = await fetch('/api/stacks/v1/create-stack-boilerplate', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -77,13 +80,12 @@ export const BasicForm = () => { } } catch (error) { console.log(error); - setMessage("error on form submission"); - + setMessage('error on form submission'); } }; if (!isUserSignedIn) { - return (); + return ; } return ( @@ -107,15 +109,14 @@ export const BasicForm = () => { {isLoading &&
Loading...
} {Message &&
{Message}
} - - {pullRequestUrl && - - -
-

You can now view your pull Request

-
- - } + + {pullRequestUrl && ( + +
+

You can now view your pull Request

+
+ + )}
); diff --git a/ui/app/components/Inputs.tsx b/ui/app/components/stacks/v1/creation/Inputs.tsx similarity index 100% rename from ui/app/components/Inputs.tsx rename to ui/app/components/stacks/v1/creation/Inputs.tsx diff --git a/ui/app/components/content.tsx b/ui/app/components/stacks/v1/creation/content.tsx similarity index 94% rename from ui/app/components/content.tsx rename to ui/app/components/stacks/v1/creation/content.tsx index 955a2f19..90b998ec 100644 --- a/ui/app/components/content.tsx +++ b/ui/app/components/stacks/v1/creation/content.tsx @@ -4,7 +4,7 @@ import { useState } from 'react'; import { useFormState } from 'react-dom'; import tw from 'tailwind-styled-components'; -import { callStack, parseFormData } from '../actions'; +import { callStack, parseFormData } from '../../../../api/stacks/v1/actions'; import InputWithButton from './input-with-button'; import Inputs from './Inputs'; import Outputs from './outputs'; diff --git a/ui/app/components/input-with-button.tsx b/ui/app/components/stacks/v1/creation/input-with-button.tsx similarity index 97% rename from ui/app/components/input-with-button.tsx rename to ui/app/components/stacks/v1/creation/input-with-button.tsx index aeb84b37..f03ff34a 100644 --- a/ui/app/components/input-with-button.tsx +++ b/ui/app/components/stacks/v1/creation/input-with-button.tsx @@ -7,7 +7,7 @@ import { IoSend } from 'react-icons/io5'; import tw from 'tailwind-styled-components'; // import SearchStacks from './search-stacks'; -import { StackDescription } from '../stacks/stack-db'; +import { StackDescription } from '../../utils/stack-db'; export const SubmitButton = () => { const { pending } = useFormStatus(); diff --git a/ui/app/components/main-content.tsx b/ui/app/components/stacks/v1/creation/main-content.tsx similarity index 100% rename from ui/app/components/main-content.tsx rename to ui/app/components/stacks/v1/creation/main-content.tsx diff --git a/ui/app/components/outputs.tsx b/ui/app/components/stacks/v1/creation/outputs.tsx similarity index 100% rename from ui/app/components/outputs.tsx rename to ui/app/components/stacks/v1/creation/outputs.tsx diff --git a/ui/app/components/stacks/elevenlabs-tts.tsx b/ui/app/components/stacks/v1/elevenlabs-tts.tsx similarity index 95% rename from ui/app/components/stacks/elevenlabs-tts.tsx rename to ui/app/components/stacks/v1/elevenlabs-tts.tsx index 448c0125..f40bdb54 100644 --- a/ui/app/components/stacks/elevenlabs-tts.tsx +++ b/ui/app/components/stacks/v1/elevenlabs-tts.tsx @@ -1,7 +1,6 @@ 'use client'; import React, { useState } from 'react'; -import ClipboardComponent from '@/app/components/clipboard'; import { IoSend } from 'react-icons/io5'; // Chat component @@ -50,7 +49,7 @@ const Chat = () => { }; async function playText(text: string) { - const response = await fetch('/api/elevenlabs-tts', { + const response = await fetch('/api/stacks/v1/elevenlabs-tts', { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/ui/app/components/stacks/get-image-description-openai.tsx b/ui/app/components/stacks/v1/get-image-description-openai.tsx similarity index 100% rename from ui/app/components/stacks/get-image-description-openai.tsx rename to ui/app/components/stacks/v1/get-image-description-openai.tsx diff --git a/ui/public/stacks/image-sharpener.tsx b/ui/app/components/stacks/v1/image-sharpener.tsx similarity index 98% rename from ui/public/stacks/image-sharpener.tsx rename to ui/app/components/stacks/v1/image-sharpener.tsx index cb7d87ab..1e4d70d2 100644 --- a/ui/public/stacks/image-sharpener.tsx +++ b/ui/app/components/stacks/v1/image-sharpener.tsx @@ -49,7 +49,7 @@ export default function ImageToMusic() { if (img) { formData.append('img', img); } - const response = await fetch('/api/image-sharpener', { + const response = await fetch('/api/stacks/v1/image-sharpener', { method: 'POST', body: formData, }); diff --git a/ui/public/stacks/image-to-music.tsx b/ui/app/components/stacks/v1/image-to-music.tsx similarity index 98% rename from ui/public/stacks/image-to-music.tsx rename to ui/app/components/stacks/v1/image-to-music.tsx index 0a4cf6ba..65f859a4 100644 --- a/ui/public/stacks/image-to-music.tsx +++ b/ui/app/components/stacks/v1/image-to-music.tsx @@ -52,7 +52,7 @@ export default function ImageToMusic() { formData.append('img', img); } formData.append('length', musicLength.toString()); - const response = await fetch('/api/image-to-music', { + const response = await fetch('/api/stacks/v1/image-to-music', { method: 'POST', body: formData, }); diff --git a/ui/app/components/stacks/instant-video-to-image.tsx b/ui/app/components/stacks/v1/instant-video-to-image.tsx similarity index 100% rename from ui/app/components/stacks/instant-video-to-image.tsx rename to ui/app/components/stacks/v1/instant-video-to-image.tsx diff --git a/ui/public/stacks/rag-pdf-with-langchain.tsx b/ui/app/components/stacks/v1/rag-pdf-with-langchain.tsx similarity index 99% rename from ui/public/stacks/rag-pdf-with-langchain.tsx rename to ui/app/components/stacks/v1/rag-pdf-with-langchain.tsx index 027a91e6..a5170b1d 100644 --- a/ui/public/stacks/rag-pdf-with-langchain.tsx +++ b/ui/app/components/stacks/v1/rag-pdf-with-langchain.tsx @@ -160,7 +160,7 @@ const RAGPDFWithLangchain = () => { setChatHistory((prev) => [...prev, `Q: ${question}`, placeholderAnswering]); try { - const response = await fetch('/api/rag-pdf-with-langchain', { + const response = await fetch('/api/stacks/v1/rag-pdf-with-langchain', { method: 'POST', body: formData, signal: signal, diff --git a/ui/public/stacks/stable-video-diffusion.tsx b/ui/app/components/stacks/v1/stable-video-diffusion.tsx similarity index 98% rename from ui/public/stacks/stable-video-diffusion.tsx rename to ui/app/components/stacks/v1/stable-video-diffusion.tsx index 07678525..86644a28 100644 --- a/ui/public/stacks/stable-video-diffusion.tsx +++ b/ui/app/components/stacks/v1/stable-video-diffusion.tsx @@ -159,7 +159,7 @@ const StableVideoDiffusion = () => { formData.append('degreeOfMotion', ensureMotion.toString()); // Call the API with FormData - const apiResponse = await fetch('/api/stable-video-diffusion', { + const apiResponse = await fetch('/api/stacks/v1/stable-video-diffusion', { method: 'POST', body: formData, // FormData is used directly here }); diff --git a/ui/app/components/stacks/text-to-qr.tsx b/ui/app/components/stacks/v1/text-to-qr.tsx similarity index 96% rename from ui/app/components/stacks/text-to-qr.tsx rename to ui/app/components/stacks/v1/text-to-qr.tsx index e0d4bc7c..449d1a9e 100644 --- a/ui/app/components/stacks/text-to-qr.tsx +++ b/ui/app/components/stacks/v1/text-to-qr.tsx @@ -17,7 +17,7 @@ export default function ImageToMusic() { setLoading(true); - const response = await fetch('/api/text-to-qr', { + const response = await fetch('/api/stacks/v1/text-to-qr', { method: 'POST', body: JSON.stringify({ qrPrompt, url }), }); diff --git a/ui/app/components/stacks/use-openai-assistant.tsx b/ui/app/components/stacks/v1/use-openai-assistant.tsx similarity index 100% rename from ui/app/components/stacks/use-openai-assistant.tsx rename to ui/app/components/stacks/v1/use-openai-assistant.tsx diff --git a/ui/app/components/stacks/website-to-music.tsx b/ui/app/components/stacks/website-to-music.tsx deleted file mode 100644 index 0a4cf6ba..00000000 --- a/ui/app/components/stacks/website-to-music.tsx +++ /dev/null @@ -1,153 +0,0 @@ -'use client'; - -import { useEffect, useRef, useState } from 'react'; - -export default function ImageToMusic() { - const [img, setImg] = useState(null); - const [llavaResponse, setLlavaResponse] = useState<{ - description: string; - prompt: string; - }>({ description: '', prompt: '' }); // Provide initial values here - const [audio, setAudio] = useState(''); - const [musicLength, setMusicLength] = useState('10'); - const [loading, setLoading] = useState(false); - const audioRef = useRef(null); - - useEffect(() => { - const fetchImage = async () => { - try { - const response = await fetch('/apocalyptic_car.png'); - const blob = await response.blob(); - const file = new File([blob], 'default_image.webp', { - type: 'image/webp', - }); - setImg(file); - } catch (error) { - console.error('Error fetching default image:', error); - } - }; - - fetchImage(); - }, []); - - const handleImageUpload = (e: React.ChangeEvent) => { - if (audio) { - setAudio(''); - } - if (e.target.files && e.target.files[0]) { - setImg(e.target.files[0]); - } - }; - - const createMusic = async () => { - if (loading) return; - if (audio) { - setAudio(''); - return; - } - - setLoading(true); - const formData = new FormData(); - if (img) { - formData.append('img', img); - } - formData.append('length', musicLength.toString()); - const response = await fetch('/api/image-to-music', { - method: 'POST', - body: formData, - }); - const data = await response.json(); - setAudio(data.audio); - setLlavaResponse(data.llavaResponse); - setLoading(false); - }; - - useEffect(() => { - if (audio) { - (audioRef.current as HTMLAudioElement | null)?.load(); - (audioRef.current as HTMLAudioElement | null)?.play(); - } - }, [audio]); - - const handleMusicLength = (e: React.ChangeEvent) => { - let value = parseInt(e.target.value, 10); - if (!isNaN(value)) { - value = Math.max(3, Math.min(30, value)); - } - setMusicLength(String(value)); - }; - - return ( -
-
- - <> - Length (sec): - setMusicLength(e.target.value)} - onBlur={handleMusicLength} - type="number" - className="ml-1 h-8 rounded border pl-1" - /> - -
-
- {img && ( - Preview - )} - {audio && ( -
-

- Image description: - {llavaResponse.description} -

-

- Inspired music: - {llavaResponse.prompt} -

-
- )} -
- -
- ); -} diff --git a/ui/app/page.tsx b/ui/app/page.tsx deleted file mode 100644 index 01609306..00000000 --- a/ui/app/page.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import tw from 'tailwind-styled-components'; - -import ContactButton from './components/ContactButton'; -import MailchimpSubscribe from './components/MailchimpSubscribe'; - -const Home: React.FC = () => { - return ( - - - - - Deploy your code with natural language - -
/ create an s3 bucket where I can upload images
-
-            / deploy this NextJS route as a lambda function and make it public
-            with the API Gateway
-          
-
- -
-
- ); -}; - -export default Home; - -const MainContainer = tw.div` - flex - flex-col - h-screen - justify-center - items-center -`; - -const Logo = tw.img` - absolute - top-4 - left-4 - w-36 -`; - -const MiddleSection = tw.div` - flex - flex-col - justify-center - items-center - w-full - md:w-[45%] - space-y-6 -`; - -const ExampleWrapper = tw.div` - bg-black - text-green-400 - font-mono - text-base - p-4 - rounded - overflow-x-auto - shadow-lg -`; - -const MainText = tw.h1` - font-bold - text-4xl -`; diff --git a/ui/app/stacks/ContactUsOnDiscord.tsx b/ui/app/stacks/ContactUsOnDiscord.tsx deleted file mode 100644 index e93dc51a..00000000 --- a/ui/app/stacks/ContactUsOnDiscord.tsx +++ /dev/null @@ -1,19 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { IoLogoDiscord } from "react-icons/io5"; - - - -export default function ContactUsOnDiscord() { - - return ( - - -
-

An unexpected error happened. Please contact us on Discord

- -
- - ); -} diff --git a/ui/app/stacks/[slug]/chat.tsx b/ui/app/stacks/[slug]/chat.tsx deleted file mode 100644 index 3b9ada26..00000000 --- a/ui/app/stacks/[slug]/chat.tsx +++ /dev/null @@ -1,161 +0,0 @@ -'use client'; - -import { useState } from 'react'; - -const LoadingComponent = () => { - return ( -
-
- -
- ); -}; - -// Chat component -export const ChatWithStack = () => { - - const [inputValue, setInputValue] = useState(''); - const [generatedFileContents, setGeneratedFileContents] = useState(''); - const [loading, setLoading] = useState(false); - const [stackResponse, setStackResponse] = useState({ - gitDiffUrl: '', - vercelLink: '', - }); // State to hold stack response - const [isPanelOpen, setIsPanelOpen] = useState(false); - const togglePanel = () => { - setIsPanelOpen(!isPanelOpen); - }; - - const postGeneratedFileContents = async (fileContent) => { - try { - const response = await fetch('/api/modify-frontend-component', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ fileContent }), - }); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const responseData = await response.json(); // Assuming the response is JSON - setStackResponse(responseData); - } catch (error) { - console.error('Error in POST /api/modify-frontend-component:', error); - } - }; - - const handleSubmit = async (event) => { - - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setGeneratedFileContents(''); - setLoading(true); - - try { - const response = await fetch('/api/suggest-frontend-component', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ brief: inputValue }), - }); - const data = await response.body; - - if (!data) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const reader = data.getReader(); - const decoder = new TextDecoder(); - let done = false; - let fullContent = ''; - - while (!done) { - const { value, done: doneReading } = await reader.read(); - done = doneReading; - const chunkValue = decoder.decode(value, { stream: !done }); - setGeneratedFileContents((prev) => prev + chunkValue); - fullContent += chunkValue; - } - - postGeneratedFileContents(fullContent); - } catch (error) { - console.error('Error during fetch:', error); - } finally { - setInputValue(''); // Clear the input field - setLoading(false); - } - } - }; - - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Type here..." - onKeyDown={(e) => { - if (e.key === 'Enter') handleSubmit(e); - }} - /> - - {loading && Might take a minute or 2 ... } - {loading && LoadingComponent()} -
-
- {stackResponse.gitDiffUrl && ( - - )} -
-
-
- ); -}; - -export default ChatWithStack; diff --git a/ui/app/stacks/[slug]/page.tsx b/ui/app/stacks/[slug]/page.tsx index 5d08761f..85a94552 100644 --- a/ui/app/stacks/[slug]/page.tsx +++ b/ui/app/stacks/[slug]/page.tsx @@ -1,8 +1,8 @@ 'use client'; +import { lazy, useEffect, useMemo, useState } from 'react'; import dynamic from 'next/dynamic'; import { useSearchParams } from 'next/navigation'; -import { lazy, useEffect, useMemo, useState } from 'react'; import { FaStar } from 'react-icons/fa'; import { FaCode } from 'react-icons/fa6'; import { IoLogoGithub } from 'react-icons/io'; @@ -10,28 +10,27 @@ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'; import tw from 'tailwind-styled-components'; -import { getStackDB, type StackDescription } from '../stack-db'; +import { + getStackDB, + type StackDescription, +} from '../../components/stacks/utils/stack-db'; // Lazy load ClipboardComponent -const ClipboardComponent = lazy(() => import('@/app/components/clipboard')); +const ClipboardComponent = lazy( + () => import('@/app/components/shared/clipboard'), +); const Link = lazy(() => import('next/link')); const MdOutlineInput = lazy(() => import('react-icons/md').then((module) => ({ default: module.MdOutlineInput, })), ); -const ChatWithStack = lazy(() => - import('./chat').then((module) => ({ default: module.ChatWithStack })), -); type StackDescriptionWithSlug = { slug: string; } & StackDescription; const Chat = ({ params }: { params: { slug: string } }) => { - const searchParams = useSearchParams(); - - const chatWithComponent = searchParams.get('chat'); const [showFrontendCode, setShowFrontendCode] = useState(true); const [backendCode, setBackendCode] = useState(''); const [frontendCode, setFrontendCode] = useState(''); @@ -51,8 +50,8 @@ const Chat = ({ params }: { params: { slug: string } }) => { if (initialStack) { const stackWithSlug = { slug: stackSlug, ...initialStack }; setStack(stackWithSlug); - const frontendPath = `/stacks/${stackSlug}.tsx`; - const backendPath = `/stacks/${stackSlug}/route.ts`; + const frontendPath = `/stacks/v1/${stackSlug}.tsx`; + const backendPath = `/stacks/stacks/v1/${stackSlug}/route.ts`; getPathText(frontendPath).then((data) => setFrontendCode(data)); getPathText(backendPath).then((data) => setBackendCode(data)); } @@ -96,7 +95,7 @@ const Chat = ({ params }: { params: { slug: string } }) => {
- +
@@ -173,7 +172,7 @@ const Chat = ({ params }: { params: { slug: string } }) => { */} { )} - {chatWithComponent && }
); diff --git a/ui/app/stacks/page.tsx b/ui/app/stacks/page.tsx index 0c4ad23e..d60d11c6 100644 --- a/ui/app/stacks/page.tsx +++ b/ui/app/stacks/page.tsx @@ -1,16 +1,16 @@ -import Link from "next/link"; -import { FaStar } from "react-icons/fa"; -import { IoLogoGithub } from "react-icons/io"; -import tw from "tailwind-styled-components"; +import Link from 'next/link'; +import { FaStar } from 'react-icons/fa'; +import { IoLogoGithub } from 'react-icons/io'; +import tw from 'tailwind-styled-components'; -import MainContent from "../components/main-content"; import { getStackDB, statusesToDisplay, type StackDescription, -} from "./stack-db"; +} from '../components/stacks/utils/stack-db'; +import MainContent from '../components/stacks/v1/creation/main-content'; -export const fetchCache = "force-no-store"; // TODO: remove this line to enable caching but without making the app completely static +export const fetchCache = 'force-no-store'; // TODO: remove this line to enable caching but without making the app completely static export const revalidate = 0; export default async function Component() { @@ -30,14 +30,14 @@ export default async function Component() { const [, stackA] = a; const [, stackB] = b; - const isAStarred = stackA.tags.includes("starred"); - const isBStarred = stackB.tags.includes("starred"); + const isAStarred = stackA.tags.includes('starred'); + const isBStarred = stackB.tags.includes('starred'); const isAPublishedNonExpansion = - stackA.tags.includes("published") && !stackA.tags.includes("expansion"); + stackA.tags.includes('published') && !stackA.tags.includes('expansion'); const isBPublishedNonExpansion = - stackB.tags.includes("published") && !stackB.tags.includes("expansion"); - const isAExpansion = stackA.tags.includes("expansion"); - const isBExpansion = stackB.tags.includes("expansion"); + stackB.tags.includes('published') && !stackB.tags.includes('expansion'); + const isAExpansion = stackA.tags.includes('expansion'); + const isBExpansion = stackB.tags.includes('expansion'); // Sorting logic if (isAStarred && !isBStarred) return -1; @@ -71,7 +71,7 @@ export default async function Component() {
{stack.name}
- {stack.tags.includes("starred") && ( + {stack.tags.includes('starred') && ( )}
diff --git a/ui/public/stacks/basic-boilerplate.tsx b/ui/public/stacks/basic-boilerplate.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/public/stacks/basic-boilerplate.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/public/stacks/boilerplate-basic/route.ts b/ui/public/stacks/boilerplate-basic/route.ts deleted file mode 100644 index d063e77a..00000000 --- a/ui/public/stacks/boilerplate-basic/route.ts +++ /dev/null @@ -1,6 +0,0 @@ -export async function POST(req: Request) { - const { input } = await req.json(); - return new Response( - JSON.stringify({ output: `You sent this message to the server: ${input}` }), - ); -} diff --git a/ui/public/stacks/cdscds.tsx b/ui/public/stacks/cdscds.tsx deleted file mode 100644 index 5267cfc6..00000000 --- a/ui/public/stacks/cdscds.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ messages: inputValue }), - }); - const data = await response.json(); - setOutput(data.output); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/public/stacks/get-roasted.tsx b/ui/public/stacks/get-roasted.tsx deleted file mode 100644 index 81d6961d..00000000 --- a/ui/public/stacks/get-roasted.tsx +++ /dev/null @@ -1,78 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { useChat } from 'ai/react'; -import { IoSend } from 'react-icons/io5'; - -export default function Chat() { - const [image, setImage] = useState( - 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Field_sparrow_in_CP_%2841484%29_%28cropped%29.jpg/733px-Field_sparrow_in_CP_%2841484%29_%28cropped%29.jpg', - ); - - const { messages, input, handleInputChange, handleSubmit } = useChat({ - api: '/api/getImageDescriptionOpenAI', - }); - - const handleImageChange = (e) => { - if (e.target.files && e.target.files[0]) { - const file = e.target.files[0]; - const reader = new FileReader(); - reader.onloadend = () => { - if (typeof reader.result === 'string') { - setImage(reader.result); - } else { - // Handle the case where the result is not a string - console.error('File could not be converted to base64 string'); - } - }; - reader.readAsDataURL(file); - } - }; - - return ( -
-
{ - handleSubmit(e, { - data: { - imageUrl: image, - }, - }); - }} - className="flex w-3/4 flex-col items-center space-y-4 md:w-1/2 lg:w-2/5" - > - - {image && Preview} -
- - -
-
-
- {messages.length > 0 - ? messages.map((m) => ( -
- {m.role === 'user' ? 'User: ' : 'AI: '} - {m.content} -
- )) - : null} -
-
- ); -} diff --git a/ui/public/stacks/hello-world.tsx b/ui/public/stacks/hello-world.tsx deleted file mode 100644 index 23e710c1..00000000 --- a/ui/public/stacks/hello-world.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -interface HelloWorldProps { - // Define any props here if needed -} - -const HelloWorld: React.FC = (props) => { - return
Hello World!
; -}; - -export default HelloWorld; diff --git a/ui/public/stacks/image-to-music/route.ts b/ui/public/stacks/image-to-music/route.ts deleted file mode 100644 index 8f1dae16..00000000 --- a/ui/public/stacks/image-to-music/route.ts +++ /dev/null @@ -1,87 +0,0 @@ -import Replicate from 'replicate'; - -const replicate = new Replicate({ - auth: process.env.REPLICATE_API_TOKEN!, -}); - -export const maxDuration = 300; - -export async function POST(request: Request) { - const form = await request.formData(); - const musicLength = Number(form.get('length')); - const imgFile = form.get('img') as Blob; - const imgBuffer = Buffer.from(await imgFile.arrayBuffer()); - const imgBase64 = imgBuffer.toString('base64'); - const imgUri = `data:${imgFile.type};base64,${imgBase64}`; - - try { - const llavaVersion = - 'yorickvp/llava-13b:e272157381e2a3bf12df3a8edd1f38d1dbd736bbb7437277c8b34175f8fce358'; - const llava: string[] = (await replicate.run(llavaVersion, { - input: { - image: imgUri, - prompt: `Describe what kind of music this image invokes. Give a brief few word description of the image, then comment on the composition of musical elements to recreate this image through music. -Example responses: -Description: Sunrise illuminating a mountain range, with rays of light breaking through clouds, creating a scene of awe and grandeur. -Music: Edo25 major G melodies that sound triumphant and cinematic, leading up to a crescendo that resolves in a 9th harmonic, beginning with a gentle, mysterious introduction that builds into an epic, sweeping climax. - -Description: A cozy, dimly lit room with a warm ambience, filled with soft shadows and a sense of quiet introspection. -Music: A jazz piece in B flat minor with a smooth saxophone solo, featuring complex rhythms and a moody, reflective atmosphere, starting with a soft, contemplative melody that evolves into an expressive, passionate finale. - -Description: A bustling, neon-lit metropolis at night, alive with vibrant energy and a sense of futuristic progress. -Music: A techno track in A minor, characterized by fast-paced electronic beats, a pulsating bassline, and futuristic synth melodies, opening with a high-energy rhythm that climaxes in a whirlwind of electronic ecstasy. - -Description: Urban streets at dusk, vibrant with street art and a pulse of lively, youthful energy. -Music: A rap beat in D minor, with heavy bass, crisp snare hits, and a catchy, repetitive melody suitable for dynamic flow, begins with a bold, assertive introduction that leads into a rhythmically complex and compelling outro. - -Description: A peaceful beach with gentle waves, clear skies, and a sense of serene joy and relaxation. -Music: A reggae tune in E major, with a relaxed tempo, characteristic off-beat rhythms, and a laid-back, feel-good vibe, starts with a soothing, cheerful melody that gradually builds into a joyful, uplifting chorus. - -Description: An electrifying rock concert, filled with intense energy, dramatic lighting, and a crowd caught up in the excitement. -Music: A heavy metal track in F sharp minor, driven by aggressive guitar riffs, fast drumming, and powerful, energetic vocals, opens with an intense, thunderous intro that crescendos into a fiery, explosive climax. - -Description: A serene, mist-covered forest at dawn, bathed in a gentle, ethereal light that creates a sense of calm and wonder. -Music: An ambient piece in A flat major, featuring slow, ethereal synth pads, creating a calm, dreamy soundscape, begins with a delicate, otherworldly sound that slowly unfolds into a serene, peaceful conclusion. - -Description: A lively party scene, bursting with color and energy, where people are lost in the moment of celebration and dance. -Music: An electronic dance music (EDM) anthem in B major, with a catchy hook, upbeat tempo, and an infectious rhythm designed for dance floors, starts with a vibrant, exhilarating beat that builds to a euphoric, dance-inducing peak.`, - }, - })) as string[]; - - const llavaPrediction: string = llava.join(''); - - console.log(llavaPrediction); - - const regex = /Description:\s*(.*?)\s*Music:\s*(.*)/s; - const match = llavaPrediction.match(regex); - if (!match) { - throw new Error('No match'); - } - const musicGenVersion = - 'meta/musicgen:b05b1dff1d8c6dc63d14b0cdb42135378dcb87f6373b0d3d341ede46e59e2b38'; - const musicGen = await replicate.run(musicGenVersion, { - input: { - classifier_free_guidance: 10, - model_version: 'stereo-melody-large', - prompt: match[2], - duration: musicLength, - }, - }); - - return new Response( - JSON.stringify({ - llavaResponse: { description: match[1], prompt: match[2] }, - audio: musicGen, - }), - { - status: 200, - headers: { 'Content-Type': 'application/json' }, - }, - ); - } catch (error) { - console.log(error); - return new Response(JSON.stringify({ error }), { - status: 500, - }); - } -} diff --git a/ui/public/stacks/load-ts-react-component.tsx b/ui/public/stacks/load-ts-react-component.tsx deleted file mode 100644 index 23e710c1..00000000 --- a/ui/public/stacks/load-ts-react-component.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -interface HelloWorldProps { - // Define any props here if needed -} - -const HelloWorld: React.FC = (props) => { - return
Hello World!
; -}; - -export default HelloWorld; diff --git a/ui/public/stacks/minimalist-agent-protocol.tsx b/ui/public/stacks/minimalist-agent-protocol.tsx deleted file mode 100644 index ccb5c11a..00000000 --- a/ui/public/stacks/minimalist-agent-protocol.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; - -export const Stack = () => { - const [inputValue, setInputValue] = useState(''); - const [generatedFileContents, setGeneratedFileContents] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setGeneratedFileContents(''); - setLoading(true); - - try { - const response = await fetch('/api/chat-with-openai-streaming', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ messages: inputValue }), - }); - const data = await response.body; - - if (!data) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const reader = data.getReader(); - const decoder = new TextDecoder(); - let done = false; - let fullContent = ''; - - while (!done) { - const { value, done: doneReading } = await reader.read(); - done = doneReading; - const chunkValue = decoder.decode(value, { stream: !done }); - setGeneratedFileContents((prev) => prev + chunkValue); - setLoading(false); - fullContent += chunkValue; - } - } catch (error) { - console.error('Error during fetch:', error); - } finally { - setInputValue(''); // Clear the input field - setLoading(false); - } - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : generatedFileContents ? ( - generatedFileContents - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default Stack; diff --git a/ui/public/stacks/modify-frontend-component/push-stack-to-github.ts b/ui/public/stacks/modify-frontend-component/push-stack-to-github.ts deleted file mode 100644 index 8a7fd5df..00000000 --- a/ui/public/stacks/modify-frontend-component/push-stack-to-github.ts +++ /dev/null @@ -1,166 +0,0 @@ -// import { stackDB } from '@/app/stacks/stack-db'; -import { Octokit } from '@octokit/rest'; -import axios from 'axios'; - -const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }); -const owner = 'stackwiseai'; -const repo = 'stackwise'; -const vercelToken = process.env.VERCEL_TOKEN; -const teamId = process.env.TEAM_ID; -const repoId = process.env.REPO_ID; -const randomString = generateRandomString(10); -const sourceBranch = process.env.VERCEL_GIT_COMMIT_REF ?? ''; // or 'master', depending on your repository -export async function pushStackToGithub( - fileContent: any, - path, - message, - isBinary = false, -) { - const branch = sourceBranch; - - const gitDiffUrl = await pushToBranch( - fileContent, - branch, - path, - message, - isBinary, - ); - console.log('gitDiffUrl', gitDiffUrl); - // const vercelLink = await deployToVercel(branch); - const vercelLink = ''; - const responseJson = { gitDiffUrl, vercelLink }; - return responseJson; -} - -async function pushToBranch(newContent, branch, path, message, isBinary) { - try { - let parentSha; - const { data: sourceBranchData } = await octokit.repos.getBranch({ - owner, - repo, - branch: sourceBranch, - }); - parentSha = sourceBranchData.commit.sha; - - const { data: commitData } = await octokit.git.getCommit({ - owner, - repo, - commit_sha: parentSha, - }); - const treeSha = commitData.tree.sha; - - const { data: treeData } = await octokit.git.createTree({ - owner, - repo, - tree: [ - isBinary - ? { - path, - mode: '100644', // blob (file) - type: 'blob', - sha: newContent, - } - : { - path, - mode: '100644', // blob (file) - type: 'blob', - content: newContent, - }, - ], - base_tree: treeSha, - }); - - // Create a new commit with the new tree and the parent commit - const { data: newCommitData } = await octokit.git.createCommit({ - owner, - repo, - message, - tree: treeData.sha, - parents: [parentSha], - }); - - console.log('Created commit:', newCommitData.sha); - - // Update the branch reference to point to the new commit - await octokit.git.updateRef({ - owner, - repo, - ref: `heads/${branch}`, - sha: newCommitData.sha, - }); - - console.log('Successfully pushed to branch:', branch); - const gitDiffLink = `https://github.com/${owner}/${repo}/compare/${sourceBranch}...${branch}`; - console.log('gitDiffLink', gitDiffLink); - return gitDiffLink; - } catch (error) { - console.error('Error pushing to branch:', error); - } -} - -function generateRandomString(length: number): string { - const characters = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - let result = ''; - const charactersLength = characters.length; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} - -async function deployToVercel(branch) { - const apiEndpoint = 'https://api.vercel.com/v9/now/deployments'; - - let config = { - method: 'post', - url: apiEndpoint + (teamId ? `?teamId=${teamId}` : ''), - headers: { - Authorization: `Bearer ${vercelToken}`, - 'Content-Type': 'application/json', - }, - data: { - name: repo, - gitSource: { - type: 'github', - ref: branch, - repo: `${owner}/${repo}`, - repoId: repoId, - }, - }, - }; - - try { - const response = await axios(config); - return `https://${response.data.alias[0]}`; - } catch (error) { - if (error.response) { - // The request was made and the server responded with a status code - // that falls out of the range of 2xx - console.error('Error Data:', error.response.data); - console.error('Error Status:', error.response.status); - console.error('Error Headers:', error.response.headers); - } else if (error.request) { - // The request was made but no response was received - console.error('Error Request:', error.request); - } else { - // Something happened in setting up the request that triggered an Error - console.error('Error Message:', error.message); - } - console.error('Error Config:', error.config); - } -} - -function sortJSONKeys(data: Record): Record { - return Object.keys(data) - .sort() - .reduce((obj: Record, key: string) => { - obj[key] = data[key]; - return obj; - }, {}); -} - -function formatSortedJSON(data: Record): string { - const sortedData = sortJSONKeys(data); - return `export const stackDB = ${JSON.stringify(sortedData, null, 2)};`; -} diff --git a/ui/public/stacks/modify-frontend-component/route.ts b/ui/public/stacks/modify-frontend-component/route.ts deleted file mode 100644 index e5298d6c..00000000 --- a/ui/public/stacks/modify-frontend-component/route.ts +++ /dev/null @@ -1,23 +0,0 @@ -export async function POST(req) { - // const json = await req.json(); - // console.log(json); - // const { fileContent, stackName } = json; - // const generatedUuid = uuidv4(); - // const randomChars = generatedUuid.replace(/-/g, "").substring(0, 7); - // const actualStackName = `${stackName}-${randomChars}`; - // const path = `ui/app/components/stacks/${actualStackName}.tsx`; - // const message = `Building ${actualStackName}`; - // const extractedContent = extractTsxOrJsx(fileContent); - // console.log(extractedContent); - // if (!extractedContent) { - // throw new Error("No tsx code found in the response"); - // } - // const responseJson = await pushStackToGithub(extractedContent, path, message); - // return Response.json(responseJson); -} - -function extractTsxOrJsx(inputString) { - const regex = /```(tsx|jsx|javascript|js|ts|typescript)\s*([\s\S]*?)\s*```/; - const match = inputString.match(regex); - return match ? match[2].trim() : inputString; -} diff --git a/ui/public/stacks/stack-example.tsx b/ui/public/stacks/stack-example.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/public/stacks/stack-example.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/public/stacks/stack-example/route.ts b/ui/public/stacks/stack-example/route.ts deleted file mode 100644 index d063e77a..00000000 --- a/ui/public/stacks/stack-example/route.ts +++ /dev/null @@ -1,6 +0,0 @@ -export async function POST(req: Request) { - const { input } = await req.json(); - return new Response( - JSON.stringify({ output: `You sent this message to the server: ${input}` }), - ); -} diff --git a/ui/public/stacks/stacks/v1/actions.ts b/ui/public/stacks/stacks/v1/actions.ts new file mode 100644 index 00000000..35277245 --- /dev/null +++ b/ui/public/stacks/stacks/v1/actions.ts @@ -0,0 +1,60 @@ +'use server'; + +const MAILCHIMP_URL = + 'https://us17.api.mailchimp.com/3.0/lists/77b1abf780/members/'; +const MAILCHIMP_API_KEY = process.env.MAILCHIMP_API_KEY; + +export const subscribeEmail = async (prevState, formData) => { + console.log(prevState, formData); + const email = formData.get('email') as string; + + const data = { + email_address: email, + status: 'subscribed', // or 'pending' for double opt-in + }; + + try { + const response = await fetch(MAILCHIMP_URL, { + method: 'POST', + headers: { + Authorization: `Basic ${btoa(`anystring:${MAILCHIMP_API_KEY}`)}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); + if (response.ok) { + console.log('Subscription successful'); + return { status: 'success' }; + } else { + const errorData = await response.json(); + console.error('Subscription error:', errorData); + return { status: 'error', error: errorData }; + } + } catch (error) { + console.error('Error:', error); + } +}; + +// import { stack } from 'stackwise'; + +export const callStack = async (prevState: any, formData: FormData) => { + const userRequest = formData.get('stack') as string; + // const message = await stack(userRequest); + const message = 'remove'; + + return message; +}; + +export const parseFormData = async (prevState: any, formData: FormData) => { + const num1 = Number(formData.get('num1')); + const num2 = Number(formData.get('num2')); + + return await multiplyNumbers(num1, num2); +}; + +/** + * Brief: Multiply two numbers together + */ +async function multiplyNumbers(num1: number, num2: number): Promise { + return num1 * num2; +} diff --git a/ui/public/stacks/basic-openai/route.ts b/ui/public/stacks/stacks/v1/basic-openai/route.ts similarity index 100% rename from ui/public/stacks/basic-openai/route.ts rename to ui/public/stacks/stacks/v1/basic-openai/route.ts diff --git a/ui/app/api/stack-example/route.ts b/ui/public/stacks/stacks/v1/boilerplate-basic/route.ts similarity index 100% rename from ui/app/api/stack-example/route.ts rename to ui/public/stacks/stacks/v1/boilerplate-basic/route.ts diff --git a/ui/public/stacks/chat-gemini-streaming-langchain/route.ts b/ui/public/stacks/stacks/v1/chat-gemini-streaming-langchain/route.ts similarity index 100% rename from ui/public/stacks/chat-gemini-streaming-langchain/route.ts rename to ui/public/stacks/stacks/v1/chat-gemini-streaming-langchain/route.ts diff --git a/ui/public/stacks/chat-with-gemini-langchain/route.ts b/ui/public/stacks/stacks/v1/chat-with-gemini-langchain/route.ts similarity index 100% rename from ui/public/stacks/chat-with-gemini-langchain/route.ts rename to ui/public/stacks/stacks/v1/chat-with-gemini-langchain/route.ts diff --git a/ui/public/stacks/chat-with-gemini-streaming/route.ts b/ui/public/stacks/stacks/v1/chat-with-gemini-streaming/route.ts similarity index 100% rename from ui/public/stacks/chat-with-gemini-streaming/route.ts rename to ui/public/stacks/stacks/v1/chat-with-gemini-streaming/route.ts diff --git a/ui/public/stacks/chat-with-gemini/route.ts b/ui/public/stacks/stacks/v1/chat-with-gemini/route.ts similarity index 100% rename from ui/public/stacks/chat-with-gemini/route.ts rename to ui/public/stacks/stacks/v1/chat-with-gemini/route.ts diff --git a/ui/public/stacks/chat-with-openai-streaming-helicone/route.ts b/ui/public/stacks/stacks/v1/chat-with-openai-streaming-helicone/route.ts similarity index 100% rename from ui/public/stacks/chat-with-openai-streaming-helicone/route.ts rename to ui/public/stacks/stacks/v1/chat-with-openai-streaming-helicone/route.ts diff --git a/ui/public/stacks/chat-with-openai-streaming-langchain/route.ts b/ui/public/stacks/stacks/v1/chat-with-openai-streaming-langchain/route.ts similarity index 100% rename from ui/public/stacks/chat-with-openai-streaming-langchain/route.ts rename to ui/public/stacks/stacks/v1/chat-with-openai-streaming-langchain/route.ts diff --git a/ui/public/stacks/chat-with-openai-streaming/route.ts b/ui/public/stacks/stacks/v1/chat-with-openai-streaming/route.ts similarity index 100% rename from ui/public/stacks/chat-with-openai-streaming/route.ts rename to ui/public/stacks/stacks/v1/chat-with-openai-streaming/route.ts diff --git a/ui/public/stacks/cover-image-and-subtitle/route.ts b/ui/public/stacks/stacks/v1/cover-image-and-subtitle/route.ts similarity index 100% rename from ui/public/stacks/cover-image-and-subtitle/route.ts rename to ui/public/stacks/stacks/v1/cover-image-and-subtitle/route.ts diff --git a/ui/public/stacks/create-stack-boilerplate/create-stack.ts b/ui/public/stacks/stacks/v1/create-stack-boilerplate/create-stack.ts similarity index 67% rename from ui/public/stacks/create-stack-boilerplate/create-stack.ts rename to ui/public/stacks/stacks/v1/create-stack-boilerplate/create-stack.ts index 2b5188b9..84db6282 100644 --- a/ui/public/stacks/create-stack-boilerplate/create-stack.ts +++ b/ui/public/stacks/stacks/v1/create-stack-boilerplate/create-stack.ts @@ -1,5 +1,5 @@ +import { getSupabaseClient } from '@/app/components/stacks/utils/stack-db'; -import { getSupabaseClient } from '@/app/stacks/stack-db'; import getFileFromGithub from './get-file-from-github'; import pushMultipleFilesToBranch from './push-multiple-files-to-branch'; @@ -8,32 +8,31 @@ export default async function createStack(data, token) { .replace(/([a-z])([A-Z])/g, '$1-$2') .replace(/\s+/g, '-') .toLowerCase(); - + const supabase = await getSupabaseClient(); const stackInfo = { name: data.name, id: stackId, description: data.description, tags: ['draft'], - } - const { data: insertedData, error } = await supabase + }; + const { data: insertedData, error } = await supabase .from('stack') - .insert([ - stackInfo - ]) + .insert([stackInfo]) .single(); - if (error) { - if (error.message.includes('duplicate key ')) { - throw new Error('This app already exists.'); - } - throw error; + if (error) { + if (error.message.includes('duplicate key ')) { + throw new Error('This app already exists.'); } - + throw error; + } + // creating api key - let path = `ui/app/components/stacks/${stackInfo.id}.tsx`; + let path = `ui/app/components/stacks/v1/${stackInfo.id}.tsx`; let message = `Frontend For ${stackInfo.id} created`; let response = await getFileFromGithub( - 'ui/public/stacks/boilerplate-basic.tsx', token + 'ui/public/stacks/v1/boilerplate-basic.tsx', + token, ); await new Promise((resolve) => setTimeout(resolve, 500)); @@ -45,10 +44,11 @@ export default async function createStack(data, token) { }, ]; - path = `ui/app/api/${stackInfo.id}/route.ts`; + path = `ui/app/api/stacks/v1/${stackInfo.id}/route.ts`; message = `Backend For ${stackInfo.id} created`; response = await getFileFromGithub( - 'ui/public/stacks/boilerplate-basic/route.ts', token + 'ui/public/stacks/v1/boilerplate-basic/route.ts', + token, ); await new Promise((resolve) => setTimeout(resolve, 500)); @@ -62,7 +62,8 @@ export default async function createStack(data, token) { message = `Preview For ${stackInfo.id} created`; response = await getFileFromGithub( - 'ui/public/stack-pictures/boilerplate-basic.png', token + 'ui/public/stack-pictures/boilerplate-basic.png', + token, ); await new Promise((resolve) => setTimeout(resolve, 500)); @@ -73,6 +74,10 @@ export default async function createStack(data, token) { }); // const sourceBranch = process.env.VERCEL_GIT_COMMIT_REF ?? ''; // or 'master', depending on your repository - const prLink = await pushMultipleFilesToBranch(filesArray, stackInfo.id, token); + const prLink = await pushMultipleFilesToBranch( + filesArray, + stackInfo.id, + token, + ); return prLink; } diff --git a/ui/public/stacks/create-stack-boilerplate/get-file-from-github.ts b/ui/public/stacks/stacks/v1/create-stack-boilerplate/get-file-from-github.ts similarity index 100% rename from ui/public/stacks/create-stack-boilerplate/get-file-from-github.ts rename to ui/public/stacks/stacks/v1/create-stack-boilerplate/get-file-from-github.ts diff --git a/ui/public/stacks/create-stack-boilerplate/push-multiple-files-to-branch.ts b/ui/public/stacks/stacks/v1/create-stack-boilerplate/push-multiple-files-to-branch.ts similarity index 100% rename from ui/public/stacks/create-stack-boilerplate/push-multiple-files-to-branch.ts rename to ui/public/stacks/stacks/v1/create-stack-boilerplate/push-multiple-files-to-branch.ts diff --git a/ui/public/stacks/create-stack-boilerplate/route.ts b/ui/public/stacks/stacks/v1/create-stack-boilerplate/route.ts similarity index 100% rename from ui/public/stacks/create-stack-boilerplate/route.ts rename to ui/public/stacks/stacks/v1/create-stack-boilerplate/route.ts diff --git a/ui/public/stacks/elevenlabs-tts/route.ts b/ui/public/stacks/stacks/v1/elevenlabs-tts/route.ts similarity index 100% rename from ui/public/stacks/elevenlabs-tts/route.ts rename to ui/public/stacks/stacks/v1/elevenlabs-tts/route.ts diff --git a/ui/public/stacks/get-image-description-openai/route.ts b/ui/public/stacks/stacks/v1/get-image-description-openai/route.ts similarity index 100% rename from ui/public/stacks/get-image-description-openai/route.ts rename to ui/public/stacks/stacks/v1/get-image-description-openai/route.ts diff --git a/ui/public/stacks/getAWSPresignedUrl/route.ts b/ui/public/stacks/stacks/v1/getAWSPresignedUrl/route.ts similarity index 100% rename from ui/public/stacks/getAWSPresignedUrl/route.ts rename to ui/public/stacks/stacks/v1/getAWSPresignedUrl/route.ts diff --git a/ui/public/stacks/image-sharpener/route.ts b/ui/public/stacks/stacks/v1/image-sharpener/route.ts similarity index 100% rename from ui/public/stacks/image-sharpener/route.ts rename to ui/public/stacks/stacks/v1/image-sharpener/route.ts diff --git a/ui/app/api/website-to-music/route.ts b/ui/public/stacks/stacks/v1/image-to-music/route.ts similarity index 100% rename from ui/app/api/website-to-music/route.ts rename to ui/public/stacks/stacks/v1/image-to-music/route.ts diff --git a/ui/public/stacks/rag-pdf-with-langchain/route.ts b/ui/public/stacks/stacks/v1/rag-pdf-with-langchain/route.ts similarity index 100% rename from ui/public/stacks/rag-pdf-with-langchain/route.ts rename to ui/public/stacks/stacks/v1/rag-pdf-with-langchain/route.ts diff --git a/ui/public/stacks/stable-video-diffusion/route.ts b/ui/public/stacks/stacks/v1/stable-video-diffusion/route.ts similarity index 100% rename from ui/public/stacks/stable-video-diffusion/route.ts rename to ui/public/stacks/stacks/v1/stable-video-diffusion/route.ts diff --git a/ui/public/stacks/text-to-qr/route.ts b/ui/public/stacks/stacks/v1/text-to-qr/route.ts similarity index 100% rename from ui/public/stacks/text-to-qr/route.ts rename to ui/public/stacks/stacks/v1/text-to-qr/route.ts diff --git a/ui/public/stacks/use-openai-assistant/route.ts b/ui/public/stacks/stacks/v1/use-openai-assistant/route.ts similarity index 100% rename from ui/public/stacks/use-openai-assistant/route.ts rename to ui/public/stacks/stacks/v1/use-openai-assistant/route.ts diff --git a/ui/public/stacks/stackwise-onboarding.tsx b/ui/public/stacks/stackwise-onboarding.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/public/stacks/stackwise-onboarding.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/public/stacks/stackwise-onboarding/route.ts b/ui/public/stacks/stackwise-onboarding/route.ts deleted file mode 100644 index d063e77a..00000000 --- a/ui/public/stacks/stackwise-onboarding/route.ts +++ /dev/null @@ -1,6 +0,0 @@ -export async function POST(req: Request) { - const { input } = await req.json(); - return new Response( - JSON.stringify({ output: `You sent this message to the server: ${input}` }), - ); -} diff --git a/ui/public/stacks/suggest-frontend-component/route.ts b/ui/public/stacks/suggest-frontend-component/route.ts deleted file mode 100644 index 64da8366..00000000 --- a/ui/public/stacks/suggest-frontend-component/route.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { OpenAIStream, StreamingTextResponse } from 'ai'; -import OpenAI from 'openai'; - -const openAIAPIKey = process.env.OPENAI_API_KEY; -const heliconeAPIKey = process.env.HELICONE_API_KEY; -const owner = 'stackwiseai'; -const repo = 'stackwise'; -const sourceBranch = process.env.VERCEL_GIT_COMMIT_REF ?? ''; -const openai = new OpenAI({ - apiKey: openAIAPIKey, - baseURL: 'https://oai.hconeai.com/v1', - defaultHeaders: { - 'Helicone-Auth': `Bearer ${heliconeAPIKey}`, - 'Helicone-Cache-Enabled': 'true', - }, -}); - -export const runtime = 'edge'; - -export async function POST(req: Request) { - // if (req.method !== 'POST') { - // res.setHeader('Allow', ['POST']); - // res.status(405).end(`Method ${req.method} Not Allowed`); - // } - const bodyText = await req.text(); - console.log('bodyText', bodyText); - const body = JSON.parse(bodyText); - - console.log('brief', body.brief); - - console.log('test'); - - const codeToChange = await getCurrentCode(); - - console.log(codeToChange, bodyText); - const systemInstructions = `You are a developer focused on writing on only one single file. -You always return a single snippet of typescript code and it's always the full code, even if it's repetitive and long. - -Please note that the code should be fully functional. No placeholders. -Always stay in the same page, you're not allowed to switch page. -please -Note You are using nextjs 14. Never remove the "use client"; on top of the file`; - - const content = `This is the app I am working with: -${codeToChange} -This is what I would like to change: -${body.brief} -Please could you rewrite entirely this file, following the system instructions ? -`; - const response = await openai.chat.completions.create({ - model: 'gpt-4-1106-preview', - messages: [ - { - role: 'system', - content: systemInstructions, - }, - { role: 'user', content: content }, - ], - stream: true, - temperature: 0, - }); - const stream = OpenAIStream(response); - - return new StreamingTextResponse(stream); -} - -async function getCurrentCode() { - try { - const response = await fetch( - `https://api.github.com/repos/${owner}/${repo}/contents/web/src/app/Home.tsx?ref=${sourceBranch}`, - { - headers: { - Authorization: `token ${process.env.GITHUB_TOKEN}`, - }, - }, - ); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data = await response.json(); - const fileContentBase64 = data.content; - console.log(fileContentBase64); - - const fileContent = Buffer.from(fileContentBase64, 'base64').toString( - 'utf-8', - ); - console.log(fileContent); - - return fileContent; - } catch (error) { - console.error(error); - } -} - -async function getChangedCode(codeToChange, brief) {} diff --git a/ui/public/stacks/test-action-4.tsx b/ui/public/stacks/test-action-4.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/public/stacks/test-boilerplate.tsx b/ui/public/stacks/test-boilerplate.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/ui/public/stacks/test-create-stack.tsx b/ui/public/stacks/test-create-stack.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/public/stacks/test-create-stack.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/public/stacks/test-stack-123.tsx b/ui/public/stacks/test-stack-123.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/public/stacks/test-stack-123.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/public/stacks/test-stack-creation-12324.tsx b/ui/public/stacks/test-stack-creation-12324.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/public/stacks/test-stack-creation-12324.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/public/stacks/test-supabase-stacks-1.tsx b/ui/public/stacks/test-supabase-stacks-1.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/public/stacks/test-supabase-stacks-1.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/public/stacks/test-supabase-stacks.tsx b/ui/public/stacks/test-supabase-stacks.tsx deleted file mode 100644 index 2fcfd8c3..00000000 --- a/ui/public/stacks/test-supabase-stacks.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useState } from 'react'; -import { IoSend } from 'react-icons/io5'; -import ReactMarkdown from 'react-markdown'; - -export const ChatWithOpenAIStreaming = () => { - const [inputValue, setInputValue] = useState(''); - const [output, setOutput] = useState(''); - const [loading, setLoading] = useState(false); - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - console.log('Submitting:', inputValue); - if (inputValue.trim()) { - setOutput(''); - setLoading(true); - - const response = await fetch('/api/boilerplate-basic', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ input: inputValue }), - }); - const data = await response.json(); - console.log('data', data); - setOutput(data.output); - setLoading(false); - } - }; - return ( -
-
-
- setInputValue(e.target.value)} - placeholder="Ask anything..." - className="focus:shadow-outline w-full rounded-full border border-gray-400 py-2 pl-4 pr-10 focus:outline-none" - onKeyDown={(e) => { - if (e.key === 'Enter') - handleSubmit(e as unknown as React.FormEvent); - }} - /> - -
-
-
- {loading ? ( - Generating... - ) : output ? ( - {output} - ) : ( -

Output here...

- )} -
-
- ); -}; - -export default ChatWithOpenAIStreaming; diff --git a/ui/public/stacks/utils/ContactButton.tsx b/ui/public/stacks/utils/ContactButton.tsx new file mode 100644 index 00000000..80c5c349 --- /dev/null +++ b/ui/public/stacks/utils/ContactButton.tsx @@ -0,0 +1,46 @@ +'use client'; + +import { useState } from 'react'; +import tw from 'tailwind-styled-components'; + +const glowingShadowStyle = { + boxShadow: `0 0 10px rgba(0, 0, 0, 0.6), + 0 0 20px rgba(0, 0, 0, 0.4), + 0 0 30px rgba(0, 0, 0, 0.2)`, +}; + +const glowingShadowHoverStyle = { + boxShadow: `0 0 10px rgba(0, 0, 0, 0.7), + 0 0 20px rgba(0, 0, 0, 0.5), + 0 0 30px rgba(0, 0, 0, 0.3), + 0 0 40px rgba(0, 0, 0, 0.1)`, +}; + +const ContactButton: React.FC = () => { + const [isHovered, setIsHovered] = useState(false); + + return ( + + ); +}; + +export default ContactButton; + +const Button = tw.button` + bg-black + text-white + font-bold + py-2 + px-4 + rounded-full + absolute + top-4 + right-4 + transition duration-300 ease-in-out +`; diff --git a/ui/public/stacks/utils/MailchimpSubscribe.tsx b/ui/public/stacks/utils/MailchimpSubscribe.tsx new file mode 100644 index 00000000..b84a2c18 --- /dev/null +++ b/ui/public/stacks/utils/MailchimpSubscribe.tsx @@ -0,0 +1,75 @@ +'use client'; + +import { useFormState, useFormStatus } from 'react-dom'; +import { IoSend } from 'react-icons/io5'; +import tw from 'tailwind-styled-components'; + +import { subscribeEmail } from '../../../api/stacks/v1/actions'; +import { Form } from '../v1/creation/input-with-button'; + +const glowingShadowStyle = { + boxShadow: `0 0 10px rgba(0, 0, 0, 0.1), + 0 0 20px rgba(0, 0, 0, 0.05)`, +}; + +const MailchimpSubscribe = () => { + const [outputState, functionAction] = useFormState(subscribeEmail, { + status: '', + }); + const { pending } = useFormStatus(); + + return ( + <> + {outputState.status === 'success' ? ( +
+ Thanks for subscribing! Join our{' '} + + Discord + +
+ ) : ( + <> +
+
+ + +
+
+ {outputState.status === 'error' &&
error.title
} + + )} + + ); +}; + +export default MailchimpSubscribe; + +const Input = tw.input` + w-full rounded-full border + py-2 pl-4 pr-10 transition + duration-300 ease-in-out + text-lg + focus:outline-none +`; + +const Button = tw.button` + focus:shadow-outline absolute + right-0 top-0 h-full cursor-pointer + rounded-r-full px-4 font-bold + text-black focus:outline-none +`; diff --git a/ui/public/stacks/utils/search-stacks.tsx b/ui/public/stacks/utils/search-stacks.tsx new file mode 100644 index 00000000..a3e592ea --- /dev/null +++ b/ui/public/stacks/utils/search-stacks.tsx @@ -0,0 +1,97 @@ +// import { useState, useEffect, useRef } from 'react'; +// import Fuse from 'fuse.js'; +// import { stackDB } from '../stacks/stack-db'; +// import { SubmitButton } from './input-with-button'; +// import { Form } from './input-with-button'; +// import { useRouter } from 'next/navigation'; + +// const SearchStacks = () => { +// const [inputValue, setInputValue] = useState(''); +// const [suggestions, setSuggestions] = useState([]); +// const router = useRouter(); +// const searchRef = useRef(null); + +// // Initialize Fuse with your stackDB data +// const fuse = new Fuse( +// Object.entries(stackDB).map(([id, { name }]) => ({ id, name })), +// { +// keys: ['name'], +// includeScore: true, +// } +// ); + +// useEffect(() => { +// if (inputValue) { +// const results = fuse.search(inputValue).map((result) => result.item.name); +// setSuggestions(results); +// } else { +// setSuggestions([]); +// } +// }, [inputValue]); + +// useEffect(() => { +// // Function to check if the click is outside the search component +// const handleClickOutside = (event) => { +// if (searchRef.current && !searchRef.current.contains(event.target)) { +// setSuggestions([]); +// } +// }; + +// // Add event listener +// document.addEventListener('mousedown', handleClickOutside); + +// // Cleanup the event listener +// return () => { +// document.removeEventListener('mousedown', handleClickOutside); +// }; +// }, [searchRef]); + +// const handleSuggestionClick = (stackName) => { +// const stackId = Object.keys(stackDB).find( +// (key) => stackDB[key].name === stackName +// ); +// if (stackId) { +// router.push(`/stacks/${stackId}`); +// } +// setInputValue(stackName); +// setSuggestions([]); +// }; + +// const handleInputFocus = () => { +// if (inputValue) { +// const results = fuse.search(inputValue).map((result) => result.item.name); +// setSuggestions(results); +// } +// }; + +// return ( +//
+//
+// setInputValue(e.target.value)} +// onFocus={handleInputFocus} +// placeholder="Search stacks" +// /> +// {suggestions.length > 0 && ( +//
    +// {suggestions.map((stackName) => ( +//
  • handleSuggestionClick(stackName)} +// className="cursor-pointer p-2 hover:bg-gray-100" +// > +// {stackName} +//
  • +// ))} +//
+// )} +// +//
+//
+// ); +// }; + +// export default SearchStacks; diff --git a/ui/public/stacks/utils/signIn.tsx b/ui/public/stacks/utils/signIn.tsx new file mode 100644 index 00000000..d7b0346f --- /dev/null +++ b/ui/public/stacks/utils/signIn.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { supabaseClient } from "./stack-db"; + + +export default function signIn() { + + async function signInWithGithub() { + + const { data, error } = await supabaseClient.auth.signInWithOAuth({ + provider: "github", + options: { + scopes: 'public_repo', + redirectTo: `${process.env.NEXT_PUBLIC_URL}/stacks/create-stack-boilerplate` + }, + }); + } + return ( + + ); +} diff --git a/ui/public/stacks/utils/signOut.tsx b/ui/public/stacks/utils/signOut.tsx new file mode 100644 index 00000000..ba78aa55 --- /dev/null +++ b/ui/public/stacks/utils/signOut.tsx @@ -0,0 +1,14 @@ +"use client"; + +import { supabaseClient } from "./stack-db"; + + + +export default function signOut() { + async function signOut() { + + const { error } = await supabaseClient.auth.signOut() + } + return ; +} + diff --git a/ui/public/stacks/utils/stack-db.ts b/ui/public/stacks/utils/stack-db.ts new file mode 100644 index 00000000..e76a8387 --- /dev/null +++ b/ui/public/stacks/utils/stack-db.ts @@ -0,0 +1,50 @@ +import { createBrowserClient } from '@supabase/ssr'; +import { createClient } from '@supabase/supabase-js'; + +type Status = 'published' | 'starred' | 'expansion'; +export const supabaseClient = createBrowserClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! +) +export async function getSupabaseClient() { + return createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL || '', + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || '', + ); +} + +export async function getStackDB() { + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL || '', + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || '', + ); + const { data: projectsArray, error } = await supabase + .from('stack') // Replace with your actual table name + .select('*'); + + if (error) { + console.error('Error fetching data:', error); + return null; + } + + const projectsObject: Record = {}; + if (projectsArray) { + projectsArray.forEach((project) => { + projectsObject[project.id] = { + name: project.name, + description: project.description, + tags: project.tags, + }; + }); + } + + return projectsObject; +} + +export interface StackDescription { + name: string; + description: string; + tags: Status[]; +} + +export const statusesToDisplay: Status[] = ['published']; diff --git a/ui/public/stacks/boilerplate-basic.tsx b/ui/public/stacks/v1/boilerplate-basic.tsx similarity index 94% rename from ui/public/stacks/boilerplate-basic.tsx rename to ui/public/stacks/v1/boilerplate-basic.tsx index 2fcfd8c3..7de0fc83 100644 --- a/ui/public/stacks/boilerplate-basic.tsx +++ b/ui/public/stacks/v1/boilerplate-basic.tsx @@ -14,7 +14,7 @@ export const ChatWithOpenAIStreaming = () => { setOutput(''); setLoading(true); - const response = await fetch('/api/boilerplate-basic', { + const response = await fetch('/api/stacks/v1/boilerplate-basic', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -53,7 +53,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : output ? ( diff --git a/ui/app/components/stacks/chat-gemini-streaming-langchain.tsx b/ui/public/stacks/v1/chat-gemini-streaming-langchain.tsx similarity index 88% rename from ui/app/components/stacks/chat-gemini-streaming-langchain.tsx rename to ui/public/stacks/v1/chat-gemini-streaming-langchain.tsx index a47b0254..91794993 100644 --- a/ui/app/components/stacks/chat-gemini-streaming-langchain.tsx +++ b/ui/public/stacks/v1/chat-gemini-streaming-langchain.tsx @@ -15,13 +15,16 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-gemini-streaming-langchain', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-gemini-streaming-langchain', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.body; if (!data) { @@ -75,7 +78,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/app/components/stacks/chat-with-gemini-langchain.tsx b/ui/public/stacks/v1/chat-with-gemini-langchain.tsx similarity index 87% rename from ui/app/components/stacks/chat-with-gemini-langchain.tsx rename to ui/public/stacks/v1/chat-with-gemini-langchain.tsx index 10d5f8c1..bdada6d0 100644 --- a/ui/app/components/stacks/chat-with-gemini-langchain.tsx +++ b/ui/public/stacks/v1/chat-with-gemini-langchain.tsx @@ -15,13 +15,16 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-with-gemini-langchain', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-with-gemini-langchain', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.json(); console.log('data', data); if (!data) { @@ -62,7 +65,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/public/stacks/chat-with-gemini-streaming.tsx b/ui/public/stacks/v1/chat-with-gemini-streaming.tsx similarity index 88% rename from ui/public/stacks/chat-with-gemini-streaming.tsx rename to ui/public/stacks/v1/chat-with-gemini-streaming.tsx index 8374f1f1..15b852d5 100644 --- a/ui/public/stacks/chat-with-gemini-streaming.tsx +++ b/ui/public/stacks/v1/chat-with-gemini-streaming.tsx @@ -15,13 +15,16 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-with-gemini-streaming', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-with-gemini-streaming', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.body; if (!data) { @@ -75,7 +78,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/app/components/stacks/chat-with-gemini.tsx b/ui/public/stacks/v1/chat-with-gemini.tsx similarity index 95% rename from ui/app/components/stacks/chat-with-gemini.tsx rename to ui/public/stacks/v1/chat-with-gemini.tsx index ae92a83e..a41faaf7 100644 --- a/ui/app/components/stacks/chat-with-gemini.tsx +++ b/ui/public/stacks/v1/chat-with-gemini.tsx @@ -14,7 +14,7 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-with-gemini', { + const response = await fetch('/api/stacks/v1/chat-with-gemini', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -74,7 +74,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/public/stacks/chat-with-openai-streaming-helicone.tsx b/ui/public/stacks/v1/chat-with-openai-streaming-helicone.tsx similarity index 88% rename from ui/public/stacks/chat-with-openai-streaming-helicone.tsx rename to ui/public/stacks/v1/chat-with-openai-streaming-helicone.tsx index 22e1261b..04afd2be 100644 --- a/ui/public/stacks/chat-with-openai-streaming-helicone.tsx +++ b/ui/public/stacks/v1/chat-with-openai-streaming-helicone.tsx @@ -14,13 +14,16 @@ export const ChatWithOpenAIStreamingHelicone = () => { setLoading(true); try { - const response = await fetch('/api/chat-openai-streaming-helicone', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-openai-streaming-helicone', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.body; if (!data) { @@ -74,7 +77,7 @@ export const ChatWithOpenAIStreamingHelicone = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/public/stacks/chat-with-openai-streaming-langchain.tsx b/ui/public/stacks/v1/chat-with-openai-streaming-langchain.tsx similarity index 100% rename from ui/public/stacks/chat-with-openai-streaming-langchain.tsx rename to ui/public/stacks/v1/chat-with-openai-streaming-langchain.tsx diff --git a/ui/public/stacks/chat-with-openai-streaming.tsx b/ui/public/stacks/v1/chat-with-openai-streaming.tsx similarity index 88% rename from ui/public/stacks/chat-with-openai-streaming.tsx rename to ui/public/stacks/v1/chat-with-openai-streaming.tsx index fd13f6ab..e95d4358 100644 --- a/ui/public/stacks/chat-with-openai-streaming.tsx +++ b/ui/public/stacks/v1/chat-with-openai-streaming.tsx @@ -14,13 +14,16 @@ export const ChatWithOpenAIStreaming = () => { setLoading(true); try { - const response = await fetch('/api/chat-with-openai-streaming', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + '/api/stacks/v1/chat-with-openai-streaming', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ messages: inputValue }), }, - body: JSON.stringify({ messages: inputValue }), - }); + ); const data = await response.body; if (!data) { @@ -74,7 +77,7 @@ export const ChatWithOpenAIStreaming = () => {
-
+
{loading ? ( Generating... ) : generatedFileContents ? ( diff --git a/ui/public/stacks/cover-image-and-subtitle.tsx b/ui/public/stacks/v1/cover-image-and-subtitle.tsx similarity index 97% rename from ui/public/stacks/cover-image-and-subtitle.tsx rename to ui/public/stacks/v1/cover-image-and-subtitle.tsx index a489d148..d40d7893 100644 --- a/ui/public/stacks/cover-image-and-subtitle.tsx +++ b/ui/public/stacks/v1/cover-image-and-subtitle.tsx @@ -23,7 +23,7 @@ export const GenerateImageAndSubtitle = () => { const file = e.target.files[0]; try { // Fetch the presigned URL - const response = await fetch('/api/getAWSPresignedUrl', { + const response = await fetch('/api/stacks/v1/getAWSPresignedUrl', { method: 'POST', body: JSON.stringify({ fileName: file.name, @@ -71,7 +71,7 @@ export const GenerateImageAndSubtitle = () => { setLoading(true); if (!video) return; - const response = await fetch('/api/cover-image-and-subtitle', { + const response = await fetch('/api/stacks/v1/cover-image-and-subtitle', { method: 'POST', body: JSON.stringify({ fileName: video.name }), }); diff --git a/ui/public/stacks/create-ai-canvas.tsx b/ui/public/stacks/v1/create-ai-canvas.tsx similarity index 100% rename from ui/public/stacks/create-ai-canvas.tsx rename to ui/public/stacks/v1/create-ai-canvas.tsx diff --git a/ui/app/components/stacks/create-stack-boilerplate.tsx b/ui/public/stacks/v1/create-stack-boilerplate.tsx similarity index 68% rename from ui/app/components/stacks/create-stack-boilerplate.tsx rename to ui/public/stacks/v1/create-stack-boilerplate.tsx index 52f3cb09..cfc20225 100644 --- a/ui/app/components/stacks/create-stack-boilerplate.tsx +++ b/ui/public/stacks/v1/create-stack-boilerplate.tsx @@ -1,38 +1,41 @@ -"use client" -import SignIn from '@/app/stacks/signIn'; -import { supabaseClient } from '@/app/stacks/stack-db'; -import Link from 'next/link'; +'use client'; + import { useEffect, useState } from 'react'; +import Link from 'next/link'; +import SignIn from '@/app/components/stacks/utils/signIn'; +import { supabaseClient } from '@/app/components/stacks/utils/stack-db'; export const BasicForm = () => { const [formData, setFormData] = useState({ - name: 'My New App', + name: 'My New App', }); const [formErrors, setFormErrors] = useState({ id: '' }); const [Message, setMessage] = useState(''); const [isUserSignedIn, setIsUserSignedIn] = useState(false); - const [username, setUsername] = useState(""); - const [token, setToken] = useState(""); - const [pullRequestUrl, setPullRequestUrl] = useState(""); + const [username, setUsername] = useState(''); + const [token, setToken] = useState(''); + const [pullRequestUrl, setPullRequestUrl] = useState(''); const [isLoading, setIsLoading] = useState(false); useEffect(() => { // Check if user is signed in async function checkUser() { try { - const session = await supabaseClient.auth.getSession() - const token = session?.data?.session?.provider_token + const session = await supabaseClient.auth.getSession(); + const token = session?.data?.session?.provider_token; if (token) { setIsUserSignedIn(true); - setUsername(session?.data?.session?.user.user_metadata.preferred_username) - setToken(token) + setUsername( + session?.data?.session?.user.user_metadata.preferred_username, + ); + setToken(token); } } catch { - console.log("Error getting user") + console.log('Error getting user'); } } - checkUser() + checkUser(); }, []); // const { getToken } = useAuth(); @@ -58,7 +61,7 @@ export const BasicForm = () => { event.preventDefault(); try { - const response = await fetch('/api/create-stack-boilerplate', { + const response = await fetch('/api/stacks/v1/create-stack-boilerplate', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -77,13 +80,12 @@ export const BasicForm = () => { } } catch (error) { console.log(error); - setMessage("error on form submission"); - + setMessage('error on form submission'); } }; if (!isUserSignedIn) { - return (); + return ; } return ( @@ -107,15 +109,14 @@ export const BasicForm = () => { {isLoading &&
Loading...
} {Message &&
{Message}
} - - {pullRequestUrl && - - -
-

You can now view your pull Request

-
- - } + + {pullRequestUrl && ( + +
+

You can now view your pull Request

+
+ + )}
); diff --git a/ui/public/stacks/v1/creation/Inputs.tsx b/ui/public/stacks/v1/creation/Inputs.tsx new file mode 100644 index 00000000..03bbbfa4 --- /dev/null +++ b/ui/public/stacks/v1/creation/Inputs.tsx @@ -0,0 +1,25 @@ +import parse from 'html-react-parser'; +import tw from 'tailwind-styled-components'; + +interface InputsProps { + formAction: (payload: FormData) => void; + state: string; +} + +const Inputs: React.FC = ({ formAction, state }) => { + return ( +
+ {parse(state)} + +
+ ); +}; + +export default Inputs; + +const Form = tw.form` + flex + flex-col + space-y-2 + w-1/2 +`; diff --git a/ui/public/stacks/v1/creation/content.tsx b/ui/public/stacks/v1/creation/content.tsx new file mode 100644 index 00000000..90b998ec --- /dev/null +++ b/ui/public/stacks/v1/creation/content.tsx @@ -0,0 +1,72 @@ +'use client'; + +import { useState } from 'react'; +import { useFormState } from 'react-dom'; +import tw from 'tailwind-styled-components'; + +import { callStack, parseFormData } from '../../../../api/stacks/v1/actions'; +import InputWithButton from './input-with-button'; +import Inputs from './Inputs'; +import Outputs from './outputs'; + +const Content = ({ stackDB }) => { + const [outputState, functionAction] = useFormState(parseFormData, null); + const [stackIO, createStack] = useFormState(callStack, { + input: '', + output: '', + }); + const [brief, setBrief] = useState(''); + + return ( + <> + + {brief ? `"${brief}"` : ''} + + {stackIO.input && ( + <> + + + + )} + + {stackIO.input && Deploy} + + ); +}; + +const Brief = tw.div` + font-bold + text-lg + mb-2 + h-8 +`; + +const Container = tw.div` + flex + justify-center + items-center + w-2/3 + space-x-6 +`; + +const DeployButton = tw.button` + text-white + bg-black + font-bold + py-3 + px-6 + rounded + mt-4 +`; + +export default Content; diff --git a/ui/public/stacks/v1/creation/input-with-button.tsx b/ui/public/stacks/v1/creation/input-with-button.tsx new file mode 100644 index 00000000..f03ff34a --- /dev/null +++ b/ui/public/stacks/v1/creation/input-with-button.tsx @@ -0,0 +1,105 @@ +'use client'; + +import { useEffect, useRef, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { useFormStatus } from 'react-dom'; +import { IoSend } from 'react-icons/io5'; +import tw from 'tailwind-styled-components'; + +// import SearchStacks from './search-stacks'; +import { StackDescription } from '../../utils/stack-db'; + +export const SubmitButton = () => { + const { pending } = useFormStatus(); + + return ( + + ); +}; + +interface InputWithButtonProps { + setBrief: React.Dispatch>; + formAction: (payload: FormData) => void; + stackDB: Record; +} + +const InputWithButton: React.FC = ({ + setBrief, + formAction, + stackDB, +}) => { + const router = useRouter(); + + const handleSubmit = (e) => { + const inputValue = e.target.elements.stack.value; + setBrief(inputValue); + }; + + const handleLuckyClick = () => { + const randomEntry = + Object.keys(stackDB)[ + Math.floor(Math.random() * Object.keys(stackDB).length) + ]; + router.push(`/stacks/${randomEntry}`); + }; + + return ( + + {/*
+
+ + +
+
*/} + {/* */} + + Take me to a random stack -{'>'} + +
+ ); +}; +const FormWrapper = tw.div` + md:w-3/4 + w-full + flex + flex-col + items-center +`; + +export const Form = tw.form` + flex + items-center + justify-center + lg:w-1/2 + md:w-3/4 + w-full + mb-2 +`; + +const LuckyButton = tw.button` + mt-3 + font-bold + border-b + transition + duration-300 + ease-in-out + transform + hover:scale-110 + text-lg +`; + +export default InputWithButton; diff --git a/ui/public/stacks/v1/creation/main-content.tsx b/ui/public/stacks/v1/creation/main-content.tsx new file mode 100644 index 00000000..8cd44e25 --- /dev/null +++ b/ui/public/stacks/v1/creation/main-content.tsx @@ -0,0 +1,47 @@ +'use server'; + +import tw from 'tailwind-styled-components'; + +import Content from './content'; + +export default async function MainContent({ stackDB }) { + return ( + + +
+ +
+ The open source AI app collection. +
+ + + +
+ ); +} + +const Container = tw.div` + flex + flex-col + justify-end + //pt-60 + pt-24 + pb-5 + //pb-10 +`; + +const TitleContainer = tw.div` + text-center +`; + +const Subtitle = tw.p` + text-lg +`; + +const MainWrapper = tw.div` + w-full + flex + flex-col + justify-center + items-center +`; diff --git a/ui/public/stacks/v1/creation/outputs.tsx b/ui/public/stacks/v1/creation/outputs.tsx new file mode 100644 index 00000000..c034fee2 --- /dev/null +++ b/ui/public/stacks/v1/creation/outputs.tsx @@ -0,0 +1,56 @@ +import tw from 'tailwind-styled-components'; + +interface InputsProps { + state: string; + value: any; +} + +const Inputs: React.FC = ({ state, value }) => { + const renderContent = () => { + // Split the string by your placeholder pattern + const parts = state.split(/({[^}]+})/).filter(Boolean); + + return parts.map((part, index) => { + if (part.startsWith('{') && part.endsWith('}')) { + // Extract and evaluate the expression + const expression = part.slice(1, -1); + + // Check if the expression is trying to access a property of 'value' + if (expression.startsWith('value.')) { + const property = expression.slice(6); + + // Check if 'value' is an object and the property is not null/undefined + if (value && typeof value === 'object' && value[property] != null) { + return value[property].toString(); + } + return ''; // Return an empty string if the property is null/undefined + } + + // Handle the direct 'value' expression + if (expression === 'value') { + return value != null ? value.toString() : ''; + } + + return ''; // If the expression cannot be evaluated, return an empty string + } else { + // If part is not an expression, return it as is + return part; + } + }); + }; + + return ( + +
+ + ); +}; + +export default Inputs; + +const Outputs = tw.form` + w-1/2 + flex + justify-center + items-center +`; diff --git a/ui/public/stacks/elevenlabs-tts.tsx b/ui/public/stacks/v1/elevenlabs-tts.tsx similarity index 95% rename from ui/public/stacks/elevenlabs-tts.tsx rename to ui/public/stacks/v1/elevenlabs-tts.tsx index 448c0125..f40bdb54 100644 --- a/ui/public/stacks/elevenlabs-tts.tsx +++ b/ui/public/stacks/v1/elevenlabs-tts.tsx @@ -1,7 +1,6 @@ 'use client'; import React, { useState } from 'react'; -import ClipboardComponent from '@/app/components/clipboard'; import { IoSend } from 'react-icons/io5'; // Chat component @@ -50,7 +49,7 @@ const Chat = () => { }; async function playText(text: string) { - const response = await fetch('/api/elevenlabs-tts', { + const response = await fetch('/api/stacks/v1/elevenlabs-tts', { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/ui/public/stacks/get-image-description-openai.tsx b/ui/public/stacks/v1/get-image-description-openai.tsx similarity index 100% rename from ui/public/stacks/get-image-description-openai.tsx rename to ui/public/stacks/v1/get-image-description-openai.tsx diff --git a/ui/app/components/stacks/image-sharpener.tsx b/ui/public/stacks/v1/image-sharpener.tsx similarity index 98% rename from ui/app/components/stacks/image-sharpener.tsx rename to ui/public/stacks/v1/image-sharpener.tsx index cb7d87ab..1e4d70d2 100644 --- a/ui/app/components/stacks/image-sharpener.tsx +++ b/ui/public/stacks/v1/image-sharpener.tsx @@ -49,7 +49,7 @@ export default function ImageToMusic() { if (img) { formData.append('img', img); } - const response = await fetch('/api/image-sharpener', { + const response = await fetch('/api/stacks/v1/image-sharpener', { method: 'POST', body: formData, }); diff --git a/ui/app/components/stacks/image-to-music.tsx b/ui/public/stacks/v1/image-to-music.tsx similarity index 98% rename from ui/app/components/stacks/image-to-music.tsx rename to ui/public/stacks/v1/image-to-music.tsx index 0a4cf6ba..65f859a4 100644 --- a/ui/app/components/stacks/image-to-music.tsx +++ b/ui/public/stacks/v1/image-to-music.tsx @@ -52,7 +52,7 @@ export default function ImageToMusic() { formData.append('img', img); } formData.append('length', musicLength.toString()); - const response = await fetch('/api/image-to-music', { + const response = await fetch('/api/stacks/v1/image-to-music', { method: 'POST', body: formData, }); diff --git a/ui/public/stacks/instant-video-to-image.tsx b/ui/public/stacks/v1/instant-video-to-image.tsx similarity index 100% rename from ui/public/stacks/instant-video-to-image.tsx rename to ui/public/stacks/v1/instant-video-to-image.tsx diff --git a/ui/app/components/stacks/rag-pdf-with-langchain.tsx b/ui/public/stacks/v1/rag-pdf-with-langchain.tsx similarity index 99% rename from ui/app/components/stacks/rag-pdf-with-langchain.tsx rename to ui/public/stacks/v1/rag-pdf-with-langchain.tsx index 027a91e6..a5170b1d 100644 --- a/ui/app/components/stacks/rag-pdf-with-langchain.tsx +++ b/ui/public/stacks/v1/rag-pdf-with-langchain.tsx @@ -160,7 +160,7 @@ const RAGPDFWithLangchain = () => { setChatHistory((prev) => [...prev, `Q: ${question}`, placeholderAnswering]); try { - const response = await fetch('/api/rag-pdf-with-langchain', { + const response = await fetch('/api/stacks/v1/rag-pdf-with-langchain', { method: 'POST', body: formData, signal: signal, diff --git a/ui/app/components/stacks/stable-video-diffusion.tsx b/ui/public/stacks/v1/stable-video-diffusion.tsx similarity index 98% rename from ui/app/components/stacks/stable-video-diffusion.tsx rename to ui/public/stacks/v1/stable-video-diffusion.tsx index 07678525..86644a28 100644 --- a/ui/app/components/stacks/stable-video-diffusion.tsx +++ b/ui/public/stacks/v1/stable-video-diffusion.tsx @@ -159,7 +159,7 @@ const StableVideoDiffusion = () => { formData.append('degreeOfMotion', ensureMotion.toString()); // Call the API with FormData - const apiResponse = await fetch('/api/stable-video-diffusion', { + const apiResponse = await fetch('/api/stacks/v1/stable-video-diffusion', { method: 'POST', body: formData, // FormData is used directly here }); diff --git a/ui/public/stacks/text-to-qr.tsx b/ui/public/stacks/v1/text-to-qr.tsx similarity index 96% rename from ui/public/stacks/text-to-qr.tsx rename to ui/public/stacks/v1/text-to-qr.tsx index e0d4bc7c..449d1a9e 100644 --- a/ui/public/stacks/text-to-qr.tsx +++ b/ui/public/stacks/v1/text-to-qr.tsx @@ -17,7 +17,7 @@ export default function ImageToMusic() { setLoading(true); - const response = await fetch('/api/text-to-qr', { + const response = await fetch('/api/stacks/v1/text-to-qr', { method: 'POST', body: JSON.stringify({ qrPrompt, url }), }); diff --git a/ui/public/stacks/use-openai-assistant.tsx b/ui/public/stacks/v1/use-openai-assistant.tsx similarity index 100% rename from ui/public/stacks/use-openai-assistant.tsx rename to ui/public/stacks/v1/use-openai-assistant.tsx diff --git a/ui/public/stacks/website-to-music.tsx b/ui/public/stacks/website-to-music.tsx deleted file mode 100644 index 0a4cf6ba..00000000 --- a/ui/public/stacks/website-to-music.tsx +++ /dev/null @@ -1,153 +0,0 @@ -'use client'; - -import { useEffect, useRef, useState } from 'react'; - -export default function ImageToMusic() { - const [img, setImg] = useState(null); - const [llavaResponse, setLlavaResponse] = useState<{ - description: string; - prompt: string; - }>({ description: '', prompt: '' }); // Provide initial values here - const [audio, setAudio] = useState(''); - const [musicLength, setMusicLength] = useState('10'); - const [loading, setLoading] = useState(false); - const audioRef = useRef(null); - - useEffect(() => { - const fetchImage = async () => { - try { - const response = await fetch('/apocalyptic_car.png'); - const blob = await response.blob(); - const file = new File([blob], 'default_image.webp', { - type: 'image/webp', - }); - setImg(file); - } catch (error) { - console.error('Error fetching default image:', error); - } - }; - - fetchImage(); - }, []); - - const handleImageUpload = (e: React.ChangeEvent) => { - if (audio) { - setAudio(''); - } - if (e.target.files && e.target.files[0]) { - setImg(e.target.files[0]); - } - }; - - const createMusic = async () => { - if (loading) return; - if (audio) { - setAudio(''); - return; - } - - setLoading(true); - const formData = new FormData(); - if (img) { - formData.append('img', img); - } - formData.append('length', musicLength.toString()); - const response = await fetch('/api/image-to-music', { - method: 'POST', - body: formData, - }); - const data = await response.json(); - setAudio(data.audio); - setLlavaResponse(data.llavaResponse); - setLoading(false); - }; - - useEffect(() => { - if (audio) { - (audioRef.current as HTMLAudioElement | null)?.load(); - (audioRef.current as HTMLAudioElement | null)?.play(); - } - }, [audio]); - - const handleMusicLength = (e: React.ChangeEvent) => { - let value = parseInt(e.target.value, 10); - if (!isNaN(value)) { - value = Math.max(3, Math.min(30, value)); - } - setMusicLength(String(value)); - }; - - return ( -
-
- - <> - Length (sec): - setMusicLength(e.target.value)} - onBlur={handleMusicLength} - type="number" - className="ml-1 h-8 rounded border pl-1" - /> - -
-
- {img && ( - Preview - )} - {audio && ( -
-

- Image description: - {llavaResponse.description} -

-

- Inspired music: - {llavaResponse.prompt} -

-
- )} -
- -
- ); -} diff --git a/ui/public/stacks/website-to-music/route.ts b/ui/public/stacks/website-to-music/route.ts deleted file mode 100644 index 8f1dae16..00000000 --- a/ui/public/stacks/website-to-music/route.ts +++ /dev/null @@ -1,87 +0,0 @@ -import Replicate from 'replicate'; - -const replicate = new Replicate({ - auth: process.env.REPLICATE_API_TOKEN!, -}); - -export const maxDuration = 300; - -export async function POST(request: Request) { - const form = await request.formData(); - const musicLength = Number(form.get('length')); - const imgFile = form.get('img') as Blob; - const imgBuffer = Buffer.from(await imgFile.arrayBuffer()); - const imgBase64 = imgBuffer.toString('base64'); - const imgUri = `data:${imgFile.type};base64,${imgBase64}`; - - try { - const llavaVersion = - 'yorickvp/llava-13b:e272157381e2a3bf12df3a8edd1f38d1dbd736bbb7437277c8b34175f8fce358'; - const llava: string[] = (await replicate.run(llavaVersion, { - input: { - image: imgUri, - prompt: `Describe what kind of music this image invokes. Give a brief few word description of the image, then comment on the composition of musical elements to recreate this image through music. -Example responses: -Description: Sunrise illuminating a mountain range, with rays of light breaking through clouds, creating a scene of awe and grandeur. -Music: Edo25 major G melodies that sound triumphant and cinematic, leading up to a crescendo that resolves in a 9th harmonic, beginning with a gentle, mysterious introduction that builds into an epic, sweeping climax. - -Description: A cozy, dimly lit room with a warm ambience, filled with soft shadows and a sense of quiet introspection. -Music: A jazz piece in B flat minor with a smooth saxophone solo, featuring complex rhythms and a moody, reflective atmosphere, starting with a soft, contemplative melody that evolves into an expressive, passionate finale. - -Description: A bustling, neon-lit metropolis at night, alive with vibrant energy and a sense of futuristic progress. -Music: A techno track in A minor, characterized by fast-paced electronic beats, a pulsating bassline, and futuristic synth melodies, opening with a high-energy rhythm that climaxes in a whirlwind of electronic ecstasy. - -Description: Urban streets at dusk, vibrant with street art and a pulse of lively, youthful energy. -Music: A rap beat in D minor, with heavy bass, crisp snare hits, and a catchy, repetitive melody suitable for dynamic flow, begins with a bold, assertive introduction that leads into a rhythmically complex and compelling outro. - -Description: A peaceful beach with gentle waves, clear skies, and a sense of serene joy and relaxation. -Music: A reggae tune in E major, with a relaxed tempo, characteristic off-beat rhythms, and a laid-back, feel-good vibe, starts with a soothing, cheerful melody that gradually builds into a joyful, uplifting chorus. - -Description: An electrifying rock concert, filled with intense energy, dramatic lighting, and a crowd caught up in the excitement. -Music: A heavy metal track in F sharp minor, driven by aggressive guitar riffs, fast drumming, and powerful, energetic vocals, opens with an intense, thunderous intro that crescendos into a fiery, explosive climax. - -Description: A serene, mist-covered forest at dawn, bathed in a gentle, ethereal light that creates a sense of calm and wonder. -Music: An ambient piece in A flat major, featuring slow, ethereal synth pads, creating a calm, dreamy soundscape, begins with a delicate, otherworldly sound that slowly unfolds into a serene, peaceful conclusion. - -Description: A lively party scene, bursting with color and energy, where people are lost in the moment of celebration and dance. -Music: An electronic dance music (EDM) anthem in B major, with a catchy hook, upbeat tempo, and an infectious rhythm designed for dance floors, starts with a vibrant, exhilarating beat that builds to a euphoric, dance-inducing peak.`, - }, - })) as string[]; - - const llavaPrediction: string = llava.join(''); - - console.log(llavaPrediction); - - const regex = /Description:\s*(.*?)\s*Music:\s*(.*)/s; - const match = llavaPrediction.match(regex); - if (!match) { - throw new Error('No match'); - } - const musicGenVersion = - 'meta/musicgen:b05b1dff1d8c6dc63d14b0cdb42135378dcb87f6373b0d3d341ede46e59e2b38'; - const musicGen = await replicate.run(musicGenVersion, { - input: { - classifier_free_guidance: 10, - model_version: 'stereo-melody-large', - prompt: match[2], - duration: musicLength, - }, - }); - - return new Response( - JSON.stringify({ - llavaResponse: { description: match[1], prompt: match[2] }, - audio: musicGen, - }), - { - status: 200, - headers: { 'Content-Type': 'application/json' }, - }, - ); - } catch (error) { - console.log(error); - return new Response(JSON.stringify({ error }), { - status: 500, - }); - } -}