feat: guesstimate platform, show guesstimate viz on question pages
This commit is contained in:
parent
05b0daa631
commit
5c248388b6
103
src/backend/platforms/guesstimate.ts
Normal file
103
src/backend/platforms/guesstimate.ts
Normal file
|
@ -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<AlgoliaQuestion[]> {
|
||||||
|
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<Question> => {
|
||||||
|
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,
|
||||||
|
};
|
|
@ -7,6 +7,7 @@ import { foretold } from "./foretold";
|
||||||
import { givewellopenphil } from "./givewellopenphil";
|
import { givewellopenphil } from "./givewellopenphil";
|
||||||
import { goodjudgment } from "./goodjudgment";
|
import { goodjudgment } from "./goodjudgment";
|
||||||
import { goodjudgmentopen } from "./goodjudgmentopen";
|
import { goodjudgmentopen } from "./goodjudgmentopen";
|
||||||
|
import { guesstimate } from "./guesstimate";
|
||||||
import { infer } from "./infer";
|
import { infer } from "./infer";
|
||||||
import { kalshi } from "./kalshi";
|
import { kalshi } from "./kalshi";
|
||||||
import { manifold } from "./manifold";
|
import { manifold } from "./manifold";
|
||||||
|
@ -72,6 +73,7 @@ export const platforms: Platform[] = [
|
||||||
givewellopenphil,
|
givewellopenphil,
|
||||||
goodjudgment,
|
goodjudgment,
|
||||||
goodjudgmentopen,
|
goodjudgmentopen,
|
||||||
|
guesstimate,
|
||||||
infer,
|
infer,
|
||||||
kalshi,
|
kalshi,
|
||||||
manifold,
|
manifold,
|
||||||
|
@ -161,21 +163,12 @@ export interface PlatformConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get frontend-safe version of platforms data
|
// get frontend-safe version of platforms data
|
||||||
export const getPlatformsConfig = (options: {
|
export const getPlatformsConfig = (): PlatformConfig[] => {
|
||||||
withGuesstimate: boolean;
|
|
||||||
}): PlatformConfig[] => {
|
|
||||||
const platformsConfig = platforms.map((platform) => ({
|
const platformsConfig = platforms.map((platform) => ({
|
||||||
name: platform.name,
|
name: platform.name,
|
||||||
label: platform.label,
|
label: platform.label,
|
||||||
color: platform.color,
|
color: platform.color,
|
||||||
}));
|
}));
|
||||||
if (options.withGuesstimate) {
|
|
||||||
platformsConfig.push({
|
|
||||||
name: "guesstimate",
|
|
||||||
label: "Guesstimate",
|
|
||||||
color: "223900",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return platformsConfig;
|
return platformsConfig;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { History, Question } from "@prisma/client";
|
||||||
|
|
||||||
import { prisma } from "../../backend/database/prisma";
|
import { prisma } from "../../backend/database/prisma";
|
||||||
import { QualityIndicators } from "../../backend/platforms";
|
import { QualityIndicators } from "../../backend/platforms";
|
||||||
|
import { guesstimate } from "../../backend/platforms/guesstimate";
|
||||||
import { builder } from "../builder";
|
import { builder } from "../builder";
|
||||||
import { PlatformObj } from "./platforms";
|
import { PlatformObj } from "./platforms";
|
||||||
|
|
||||||
|
@ -144,6 +145,13 @@ builder.queryField("question", (t) =>
|
||||||
id: t.arg({ type: "ID", required: true }),
|
id: t.arg({ type: "ID", required: true }),
|
||||||
},
|
},
|
||||||
resolve: async (parent, args) => {
|
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({
|
return await prisma.question.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id: String(args.id),
|
id: String(args.id),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { guesstimate } from "../../backend/platforms/guesstimate";
|
||||||
import { AlgoliaQuestion } from "../../backend/utils/algolia";
|
import { AlgoliaQuestion } from "../../backend/utils/algolia";
|
||||||
import searchGuesstimate from "../../web/worker/searchGuesstimate";
|
|
||||||
import searchWithAlgolia from "../../web/worker/searchWithAlgolia";
|
import searchWithAlgolia from "../../web/worker/searchWithAlgolia";
|
||||||
import { builder } from "../builder";
|
import { builder } from "../builder";
|
||||||
import { QuestionObj } from "./questions";
|
import { QuestionObj } from "./questions";
|
||||||
|
@ -54,7 +54,7 @@ builder.queryField("searchQuestions", (t) =>
|
||||||
const [responsesNotGuesstimate, responsesGuesstimate] =
|
const [responsesNotGuesstimate, responsesGuesstimate] =
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
unawaitedAlgoliaResponse,
|
unawaitedAlgoliaResponse,
|
||||||
searchGuesstimate(query),
|
guesstimate.search(query),
|
||||||
]); // faster than two separate requests
|
]); // faster than two separate requests
|
||||||
results = [...responsesNotGuesstimate, ...responsesGuesstimate];
|
results = [...responsesNotGuesstimate, ...responsesGuesstimate];
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -13,7 +13,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
const [ssrCache, client] = ssrUrql();
|
const [ssrCache, client] = ssrUrql();
|
||||||
const urlQuery = context.query;
|
const urlQuery = context.query;
|
||||||
|
|
||||||
const platformsConfig = getPlatformsConfig({ withGuesstimate: true });
|
const platformsConfig = getPlatformsConfig();
|
||||||
|
|
||||||
const defaultQueryParameters: QueryParameters = {
|
const defaultQueryParameters: QueryParameters = {
|
||||||
query: "",
|
query: "",
|
||||||
|
|
|
@ -74,7 +74,17 @@ const LargeQuestionCard: React.FC<{
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<HistoryChart question={question} />
|
{question.platform.id === "guesstimate" ? (
|
||||||
|
<a className="no-underline" href={question.url} target="_blank">
|
||||||
|
<img
|
||||||
|
className="rounded-sm"
|
||||||
|
src={question.visualization}
|
||||||
|
alt="Guesstimate Screenshot"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<HistoryChart question={question} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
/* Imports */
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
import { AlgoliaQuestion } from "../../backend/utils/algolia";
|
|
||||||
|
|
||||||
/* Definitions */
|
|
||||||
const urlEndPoint =
|
|
||||||
"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";
|
|
||||||
|
|
||||||
/* Body */
|
|
||||||
|
|
||||||
export default async function searchGuesstimate(
|
|
||||||
query
|
|
||||||
): Promise<AlgoliaQuestion[]> {
|
|
||||||
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))
|
|
Loading…
Reference in New Issue
Block a user