Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "plot-ai",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:3000",
"type": "module",
"scripts": {
"build": "next build",
Expand Down Expand Up @@ -40,6 +41,7 @@
"next": "^14.2.2",
"next-auth": "^4.24.7",
"next-themes": "^0.3.0",
"nextjs-cors": "^2.2.0",
"radix-ui": "^1.0.1",
"react": "18.2.0",
"react-dom": "18.2.0",
Expand All @@ -48,6 +50,7 @@
"server-only": "^0.0.1",
"sonner": "^1.4.41",
"superjson": "^2.2.1",
"swr": "^2.2.5",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.23.0"
Expand Down
11 changes: 7 additions & 4 deletions src/app/api/trpc/[trpc]/route.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { httpBatchLink } from "@trpc/client";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { type NextRequest } from "next/server";
import { NextResponse, type NextRequest } from "next/server";

import { env } from "~/env";
import { appRouter } from "~/server/api/root";
import { createTRPCContext } from "~/server/api/trpc";

import { NextApiResponse } from "next";

/**
* This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
* handling a HTTP request (e.g. when you make requests from Client Components).
Expand All @@ -16,8 +18,8 @@ const createContext = async (req: NextRequest) => {
});
};

const handler = (req: NextRequest) =>
fetchRequestHandler({
const handler = async (req: NextRequest, res: NextApiResponse) => {
return fetchRequestHandler({
endpoint: "/api/trpc",
req,
router: appRouter,
Expand All @@ -26,10 +28,11 @@ const handler = (req: NextRequest) =>
env.NODE_ENV === "development"
? ({ path, error }) => {
console.error(
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`,
);
}
: undefined,
});
};

export { handler as GET, handler as POST };
174 changes: 174 additions & 0 deletions src/app/models/_components/gpt-search.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// @ts-nocheck
import React, { useState } from "react";
import { useModelNodesContext } from "~/app/_context/model-context";
import { Button } from "~/components/ui/button";
import { api } from "~/trpc/react";

interface GptSearchPageProps {
onResults: (results: JSON) => JSON;
}

const GptSearchPage: React.FC<GptSearchPageProps> = ({ onResults }) => {
const [query, setQuery] = useState<string>("");
const [searchResult, setSearchResult] = useState<string | null>(null);
const fetchProperties = api.propertySearch.search.useMutation();
const nodes = {
nodes: [
{
id: "0",
type: "blockComp",
data: [
{
id: "vy4wuo965iq",
section: "Property Details",
value: "deckArea",
label: "Deck Area",
format: "size",
input: 0,
operator: "",
visible: true,
},
{
id: "ej2pk6l6lsj",
section: "Property Details",
value: "deckArea",
label: "Deck Area",
format: "size",
input: 0,
operator: "",
visible: true,
},
{
id: "1yx5rx7c9wfh",
section: "Property Details",
value: "squareFeet",
label: "Square Feet",
format: "size",
input: 0,
operator: "",
visible: true,
},
{
id: "09ushjuob9px",
section: "Property Details",
value: "unitsCount",
label: "Unit Count",
format: "number",
input: 0,
operator: "",
visible: true,
},
],
dragHandle: ".custom-drag-handle",
style: {
border: "2px solid #ddd",
background: "white",
borderRadius: "8px",
},
position: { x: 0, y: 0 },
width: 276,
height: 196,
},
{
id: "1",
type: "blockComp",
dragHandle: ".custom-drag-handle",
position: { x: 311.5153248642067, y: 108.71122718380283 },
style: {
border: "2px solid #ddd",
background: "white",
borderRadius: "8px",
},
data: [
{
id: "3n36fktrp4y",
section: "Financial Valuation",
value: "assessedLandValue",
label: "Assessed Land Value",
format: "USD",
input: 0,
operator: "",
visible: true,
},
{
id: "raeiz6vfwu",
section: "Financial Valuation",
value: "priorSaleAmount",
label: "Prior Sale Amount",
format: "USD",
input: 0,
operator: "",
visible: true,
},
{
id: "qoa6conq1o",
section: "Financial Valuation",
value: "assessedValue",
label: "Assessed Value",
format: "USD",
input: 0,
operator: "",
visible: true,
},
],
width: 276,
height: 196,
},
],
edges: [{ id: "1", source: "0", target: "1" }],
viewport: {
x: -251.76669469951742,
y: -24.53523350178338,
zoom: 1.3571296849803665,
},
};

const handleSubmit: React.FormEventHandler<HTMLFormElement> = (e) => {
const result = fetchProperties.mutate({
nodes: JSON.stringify(nodes),
userInput: query,
});
console.log(result);
onResults(result);
};

return (
<div className="flex h-screen flex-col items-center justify-center">
<h1 className="mb-10 scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">
Use AI to find properties:
</h1>
<form
className="w-full max-w-md rounded-lg bg-white p-6 shadow-lg"
onSubmit={handleSubmit}
>
<div className="mb-4">
<label
htmlFor="search"
className="mb-2 block text-sm font-bold text-gray-700"
>
Search:
</label>
<input
type="text"
id="search"
className="w-full rounded-md border border-gray-300 px-3 py-2 leading-tight focus:border-blue-500 focus:outline-none"
placeholder="Enter your search query..."
value={query}
onChange={(e) => setQuery(e.target.value)}
required
/>
</div>
<Button type="submit">Submit</Button>
</form>
{searchResult && (
<div className="mt-8">
<h2 className="mb-2 text-xl font-bold">Search Result:</h2>
<p className="text-gray-800">{searchResult.result}</p>
</div>
)}
</div>
);
};

export default GptSearchPage;

30 changes: 30 additions & 0 deletions src/app/models/_components/property-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";

const PropertyCard = ({ imageUrl, price, address, propDetails }) => {
return (
<div className="flex justify-center">
<div className="w-400">
<div className="flex overflow-hidden rounded-lg bg-white shadow-lg">
<div className="flex h-40 w-40 items-center justify-center">
<img
className="h-full w-full object-cover"
src={imageUrl}
alt={address}
/>
</div>
<div className="flex flex-col justify-between p-4">
<div>
<h2 className="mb-2 text-xl font-semibold">${price}</h2>
<p className="mb-4 text-gray-700">{address}</p>
</div>
{propDetails?.map((param) => (
<p className="font-bold text-gray-800">Param</p>
))}
</div>
</div>
</div>
</div>
);
};

export default PropertyCard;
42 changes: 42 additions & 0 deletions src/app/models/editor/[modelId]/search/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// @ts-nocheck
"use client"
import React, { useState } from "react";
import GptSearchPage from "~/app/models/_components/gpt-search";
import PropertyCard from "~/app/models/_components/property-card";



function Page() {
const [propertyData, setPropertyData] = useState([]);

function onResultUpdate(data) {
// The data returned will be an array of key value pairs ex: ["assessedValue": "10000"]
/* We could possibly format the returned data to be:

["address": "example address",
"price": "10000000",
"propDetails": {[]}]

Then use a map to unravel the data to the PropertyCard component and populate it with whatever params we need

*/
setPropertyData(data);
};

return (
<div>
{propertyData.map((property, index) => (
<PropertyCard
key={index}
address={property.address}
propDetails={property.propDetails}
price={property.price}
imageUrl={property.imageUrl}
/>
))}
<GptSearchPage onResults={onResultUpdate}></GptSearchPage>
</div>
);
}

export default Page;
5 changes: 3 additions & 2 deletions src/server/api/root.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { postRouter } from "~/server/api/routers/post";
import { modelsRouter } from "~/server/api/routers/models";
import { createCallerFactory, createTRPCRouter } from "~/server/api/trpc";
import { propertySearchRouter } from "./routers/propertySearch";

/**
* This is the primary router for your server.
Expand All @@ -9,7 +10,8 @@ import { createCallerFactory, createTRPCRouter } from "~/server/api/trpc";
*/
export const appRouter = createTRPCRouter({
post: postRouter,
models: modelsRouter
models: modelsRouter,
propertySearch: propertySearchRouter,
});

// export type definition of API
Expand All @@ -23,4 +25,3 @@ export type AppRouter = typeof appRouter;
* ^? Post[]
*/
export const createCaller = createCallerFactory(appRouter);

Loading