diff --git a/src/backend/platforms/guesstimate.ts b/src/backend/platforms/guesstimate.ts new file mode 100644 index 0000000..d61ed7e --- /dev/null +++ b/src/backend/platforms/guesstimate.ts @@ -0,0 +1,103 @@ +import axios from "axios"; +import { parseISO } from "date-fns"; + +/* Imports */ +import { Question } from "@prisma/client"; + +import { AlgoliaQuestion } from "../../backend/utils/algolia"; +import { prisma } from "../database/prisma"; +import { Platform } from "./"; + +/* Definitions */ +const searchEndpoint = + "https://m629r9ugsg-dsn.algolia.net/1/indexes/Space_production/query?x-algolia-agent=Algolia%20for%20vanilla%20JavaScript%203.32.1&x-algolia-application-id=M629R9UGSG&x-algolia-api-key=4e893740a2bd467a96c8bfcf95b2809c"; + +const apiEndpoint = "https://guesstimate.herokuapp.com"; + +/* Body */ + +const modelToQuestion = (model: any): Question => { + const { description } = model; + // const description = model.description + // ? model.description.replace(/\n/g, " ").replace(/ /g, " ") + // : ""; + const stars = description.length > 250 ? 2 : 1; + const timestamp = parseISO(model.created_at); + const q: Question = { + id: `guesstimate-${model.id}`, + title: model.name, + url: `https://www.getguesstimate.com/models/${model.id}`, + timestamp, + platform: "guesstimate", + description, + options: [], + qualityindicators: { + stars, + numforecasts: 1, + numforecasters: 1, + }, + extra: { + visualization: model.big_screenshot, + }, + // ranking: 10 * (index + 1) - 0.5, //(model._rankingInfo - 1*index)// hack + }; + return q; +}; + +async function search(query: string): Promise { + const response = await axios({ + url: searchEndpoint, + headers: { + Accept: "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }, + data: `{\"params\":\"query=${query.replace( + / /g, + "%20" + )}&hitsPerPage=20&page=0&getRankingInfo=true\"}`, + method: "POST", + }); + + const models: any[] = response.data.hits; + const mappedModels: AlgoliaQuestion[] = models.map((model) => { + const q = modelToQuestion(model); + return { + ...q, + timestamp: String(q.timestamp), + }; + }); + + // filter for duplicates. Surprisingly common. + let uniqueTitles = []; + let uniqueModels: AlgoliaQuestion[] = []; + for (let model of mappedModels) { + if (!uniqueTitles.includes(model.title) && !model.title.includes("copy")) { + uniqueModels.push(model); + uniqueTitles.push(model.title); + } + } + + return uniqueModels; +} + +const fetchQuestion = async (id: number): Promise => { + const response = await axios({ url: `${apiEndpoint}/spaces/${id}` }); + let q = modelToQuestion(response.data); + q = await prisma.question.upsert({ + where: { id: q.id }, + create: q, + update: q, + }); + return q; +}; + +export const guesstimate: Platform & { + search: typeof search; + fetchQuestion: typeof fetchQuestion; +} = { + name: "guesstimate", + label: "Guesstimate", + color: "#223900", + search, + fetchQuestion, +}; diff --git a/src/backend/platforms/index.ts b/src/backend/platforms/index.ts index 2f6e6f6..dcaa265 100644 --- a/src/backend/platforms/index.ts +++ b/src/backend/platforms/index.ts @@ -7,6 +7,7 @@ import { foretold } from "./foretold"; import { givewellopenphil } from "./givewellopenphil"; import { goodjudgment } from "./goodjudgment"; import { goodjudgmentopen } from "./goodjudgmentopen"; +import { guesstimate } from "./guesstimate"; import { infer } from "./infer"; import { kalshi } from "./kalshi"; import { manifold } from "./manifold"; @@ -72,6 +73,7 @@ export const platforms: Platform[] = [ givewellopenphil, goodjudgment, goodjudgmentopen, + guesstimate, infer, kalshi, manifold, @@ -161,21 +163,12 @@ export interface PlatformConfig { } // get frontend-safe version of platforms data -export const getPlatformsConfig = (options: { - withGuesstimate: boolean; -}): PlatformConfig[] => { +export const getPlatformsConfig = (): PlatformConfig[] => { const platformsConfig = platforms.map((platform) => ({ name: platform.name, label: platform.label, color: platform.color, })); - if (options.withGuesstimate) { - platformsConfig.push({ - name: "guesstimate", - label: "Guesstimate", - color: "223900", - }); - } return platformsConfig; }; diff --git a/src/graphql/schema/questions.ts b/src/graphql/schema/questions.ts index ed39ab6..f3ec7e2 100644 --- a/src/graphql/schema/questions.ts +++ b/src/graphql/schema/questions.ts @@ -2,6 +2,7 @@ import { History, Question } from "@prisma/client"; import { prisma } from "../../backend/database/prisma"; import { QualityIndicators } from "../../backend/platforms"; +import { guesstimate } from "../../backend/platforms/guesstimate"; import { builder } from "../builder"; import { PlatformObj } from "./platforms"; @@ -144,6 +145,13 @@ builder.queryField("question", (t) => id: t.arg({ type: "ID", required: true }), }, resolve: async (parent, args) => { + const parts = String(args.id).split("-"); + const [platform, id] = [parts[0], parts.slice(1).join("-")]; + if (platform === "guesstimate") { + const q = await guesstimate.fetchQuestion(Number(id)); + console.log(q); + return q; + } return await prisma.question.findUnique({ where: { id: String(args.id), diff --git a/src/graphql/schema/search.ts b/src/graphql/schema/search.ts index ca6a41a..4676b45 100644 --- a/src/graphql/schema/search.ts +++ b/src/graphql/schema/search.ts @@ -1,5 +1,5 @@ +import { guesstimate } from "../../backend/platforms/guesstimate"; import { AlgoliaQuestion } from "../../backend/utils/algolia"; -import searchGuesstimate from "../../web/worker/searchGuesstimate"; import searchWithAlgolia from "../../web/worker/searchWithAlgolia"; import { builder } from "../builder"; import { QuestionObj } from "./questions"; @@ -54,7 +54,7 @@ builder.queryField("searchQuestions", (t) => const [responsesNotGuesstimate, responsesGuesstimate] = await Promise.all([ unawaitedAlgoliaResponse, - searchGuesstimate(query), + guesstimate.search(query), ]); // faster than two separate requests results = [...responsesNotGuesstimate, ...responsesGuesstimate]; } else { diff --git a/src/pages/index.tsx b/src/pages/index.tsx index b9b568f..b8cb2ae 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -13,7 +13,7 @@ export const getServerSideProps: GetServerSideProps = async ( const [ssrCache, client] = ssrUrql(); const urlQuery = context.query; - const platformsConfig = getPlatformsConfig({ withGuesstimate: true }); + const platformsConfig = getPlatformsConfig(); const defaultQueryParameters: QueryParameters = { query: "", diff --git a/src/web/questions/pages/QuestionPage.tsx b/src/web/questions/pages/QuestionPage.tsx index cde36f5..01da866 100644 --- a/src/web/questions/pages/QuestionPage.tsx +++ b/src/web/questions/pages/QuestionPage.tsx @@ -74,7 +74,17 @@ const LargeQuestionCard: React.FC<{
- + {question.platform.id === "guesstimate" ? ( + + Guesstimate Screenshot + + ) : ( + + )}
{ - const response = await axios({ - url: urlEndPoint, - // credentials: "omit", - headers: { - // "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0", - Accept: "application/json", - "Accept-Language": "en-US,en;q=0.5", - "content-type": "application/x-www-form-urlencoded", - }, - data: `{\"params\":\"query=${query.replace( - / /g, - "%20" - )}&hitsPerPage=20&page=0&getRankingInfo=true\"}`, - method: "POST", - }); - - const models: any[] = response.data.hits; - const mappedModels: AlgoliaQuestion[] = models.map((model, index) => { - const description = model.description - ? model.description.replace(/\n/g, " ").replace(/ /g, " ") - : ""; - const stars = description.length > 250 ? 2 : 1; - const q: AlgoliaQuestion = { - id: `guesstimate-${model.id}`, - title: model.name, - url: `https://www.getguesstimate.com/models/${model.id}`, - timestamp: model.created_at, // TODO - check that format matches - platform: "guesstimate", - description, - options: [], - qualityindicators: { - stars, - numforecasts: 1, - numforecasters: 1, - }, - extra: { - visualization: model.big_screenshot, - }, - // ranking: 10 * (index + 1) - 0.5, //(model._rankingInfo - 1*index)// hack - }; - return q; - }); - - // filter for duplicates. Surprisingly common. - let uniqueTitles = []; - let uniqueModels: AlgoliaQuestion[] = []; - for (let model of mappedModels) { - if (!uniqueTitles.includes(model.title) && !model.title.includes("copy")) { - uniqueModels.push(model); - uniqueTitles.push(model.title); - } - } - - console.log(uniqueModels); - return uniqueModels; -} - -// searchGuesstimate("COVID-19").then(guesstimateModels => console.log(guesstimateModels))