fix: catch metaculus errors
Current code isn't particularly resilient to API changes.
This commit is contained in:
parent
83a01e6156
commit
fc9c222a44
|
@ -211,15 +211,17 @@ const fetchAndValidate = async <T = unknown>(
|
|||
url: string,
|
||||
validator: ValidateFunction<T>
|
||||
): Promise<T> => {
|
||||
console.log(url);
|
||||
// console.log(url);
|
||||
const data = await fetchWithRetries<object>(url);
|
||||
if (validator(data)) {
|
||||
return data;
|
||||
}
|
||||
}else{
|
||||
console.log(data)
|
||||
throw new Error(
|
||||
`Response validation for url ${url} failed: ` +
|
||||
JSON.stringify(validator.errors)
|
||||
JSON.stringify(validator.errors, null, 4)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export async function fetchApiQuestions(
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Error from "next/error";
|
||||
import {FetchedQuestion, Platform} from "..";
|
||||
import {average} from "../../../utils";
|
||||
import {sleep} from "../../utils/sleep";
|
||||
|
@ -7,16 +8,14 @@ import {
|
|||
ApiPredictable,
|
||||
ApiQuestion,
|
||||
fetchApiQuestions,
|
||||
fetchSingleApiQuestion,
|
||||
fetchSingleApiQuestion
|
||||
} from "./api";
|
||||
|
||||
const platformName = "metaculus";
|
||||
const now = new Date().toISOString();
|
||||
const SLEEP_TIME = 1000;
|
||||
|
||||
async function apiQuestionToFetchedQuestions(
|
||||
apiQuestion: ApiQuestion
|
||||
): Promise<FetchedQuestion[]> {
|
||||
async function apiQuestionToFetchedQuestions(apiQuestion: ApiQuestion): Promise<FetchedQuestion[]> {
|
||||
// one item can expand:
|
||||
// - to 0 questions if we don't want it;
|
||||
// - to 1 question if it's a simple forecast
|
||||
|
@ -32,9 +31,8 @@ async function apiQuestionToFetchedQuestions(
|
|||
return false;
|
||||
};
|
||||
|
||||
const buildFetchedQuestion = (
|
||||
q: ApiPredictable & ApiCommon
|
||||
): Omit<FetchedQuestion, "url" | "description" | "title"> => {
|
||||
const buildFetchedQuestion = (q : ApiPredictable & ApiCommon) : Omit < FetchedQuestion,
|
||||
"url" | "description" | "title" > => {
|
||||
const isBinary = q.possibilities.type === "binary";
|
||||
let options: FetchedQuestion["options"] = [];
|
||||
if (isBinary) {
|
||||
|
@ -44,30 +42,31 @@ async function apiQuestionToFetchedQuestions(
|
|||
{
|
||||
name: "Yes",
|
||||
probability: probability,
|
||||
type: "PROBABILITY",
|
||||
},
|
||||
{
|
||||
type: "PROBABILITY"
|
||||
}, {
|
||||
name: "No",
|
||||
probability: 1 - probability,
|
||||
type: "PROBABILITY",
|
||||
type: "PROBABILITY"
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: `${platformName}-${q.id}`,
|
||||
id: `${platformName}-${
|
||||
q.id
|
||||
}`,
|
||||
options,
|
||||
qualityindicators: {
|
||||
numforecasts: q.number_of_predictions,
|
||||
numforecasts: q.number_of_predictions
|
||||
},
|
||||
extra: {
|
||||
resolution_data: {
|
||||
publish_time: apiQuestion.publish_time,
|
||||
resolution: apiQuestion.resolution,
|
||||
close_time: apiQuestion.close_time,
|
||||
resolve_time: apiQuestion.resolve_time,
|
||||
},
|
||||
},
|
||||
resolve_time: apiQuestion.resolve_time
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -77,44 +76,64 @@ async function apiQuestionToFetchedQuestions(
|
|||
if (apiQuestionDetails.type !== "group") {
|
||||
throw new Error("Expected `group` type"); // shouldn't happen, this is mostly for typescript
|
||||
}
|
||||
return (apiQuestionDetails.sub_questions || [])
|
||||
.filter((q) => !skip(q))
|
||||
.map((sq) => {
|
||||
try{
|
||||
let result = (apiQuestionDetails.sub_questions || []).filter((q) => ! skip(q)).map((sq) => {
|
||||
const tmp = buildFetchedQuestion(sq);
|
||||
return {
|
||||
... tmp,
|
||||
title: `${apiQuestion.title} (${sq.title})`,
|
||||
title: `${
|
||||
apiQuestion.title
|
||||
} (${
|
||||
sq.title
|
||||
})`,
|
||||
description: apiQuestionDetails.description || "",
|
||||
url: `https://www.metaculus.com${apiQuestion.page_url}?sub-question=${sq.id}`,
|
||||
url: `https://www.metaculus.com${
|
||||
apiQuestion.page_url
|
||||
}?sub-question=${
|
||||
sq.id
|
||||
}`
|
||||
};
|
||||
});
|
||||
return result
|
||||
}catch(error){
|
||||
console.log(error)
|
||||
return []
|
||||
}
|
||||
} else if (apiQuestion.type === "forecast") {
|
||||
if (apiQuestion.group) {
|
||||
return []; // sub-question, should be handled on the group level
|
||||
}
|
||||
if (skip(apiQuestion)) {
|
||||
console.log(`- [Skipping]: ${
|
||||
apiQuestion.title
|
||||
}`)
|
||||
/*console.log(`Close time: ${
|
||||
apiQuestion.close_time
|
||||
}, resolve time: ${
|
||||
apiQuestion.resolve_time
|
||||
}`)*/
|
||||
return [];
|
||||
}
|
||||
|
||||
await sleep(SLEEP_TIME);
|
||||
const apiQuestionDetails = await fetchSingleApiQuestion(apiQuestion.id);
|
||||
try{
|
||||
const tmp = buildFetchedQuestion(apiQuestion);
|
||||
return [
|
||||
{
|
||||
return [{
|
||||
... tmp,
|
||||
title: apiQuestion.title,
|
||||
description: apiQuestionDetails.description || "",
|
||||
url: "https://www.metaculus.com" + apiQuestion.page_url,
|
||||
},
|
||||
];
|
||||
url: "https://www.metaculus.com" + apiQuestion.page_url
|
||||
},];
|
||||
}catch(error){
|
||||
console.log(error)
|
||||
return []
|
||||
}
|
||||
} else {
|
||||
if (apiQuestion.type !== "claim") {
|
||||
// should never happen, since `discriminator` in JTD schema causes a strict runtime check
|
||||
console.log(
|
||||
`Unknown metaculus question type: ${
|
||||
if (apiQuestion.type !== "claim") { // should never happen, since `discriminator` in JTD schema causes a strict runtime check
|
||||
console.log(`Unknown metaculus question type: ${
|
||||
(apiQuestion as any).type
|
||||
}, skipping`
|
||||
);
|
||||
}, skipping`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
@ -125,19 +144,19 @@ export const metaculus: Platform<"id" | "debug"> = {
|
|||
label: "Metaculus",
|
||||
color: "#006669",
|
||||
version: "v2",
|
||||
fetcherArgs: ["id", "debug"],
|
||||
fetcherArgs: [
|
||||
"id", "debug"
|
||||
],
|
||||
async fetcher(opts) {
|
||||
let allQuestions: FetchedQuestion[] = [];
|
||||
|
||||
if (opts.args ?. id) {
|
||||
console.log("Using optional id arg.")
|
||||
const id = Number(opts.args.id);
|
||||
const apiQuestion = await fetchSingleApiQuestion(id);
|
||||
const questions = await apiQuestionToFetchedQuestions(apiQuestion);
|
||||
console.log(questions);
|
||||
return {
|
||||
questions,
|
||||
partial: true,
|
||||
};
|
||||
return {questions, partial: true};
|
||||
}
|
||||
|
||||
let next: string |null = "https://www.metaculus.com/api2/questions/";
|
||||
|
@ -148,13 +167,16 @@ export const metaculus: Platform<"id" | "debug"> = {
|
|||
await sleep(SLEEP_TIME);
|
||||
const apiQuestions: ApiMultipleQuestions = await fetchApiQuestions(next);
|
||||
const results = apiQuestions.results;
|
||||
|
||||
// console.log(results)
|
||||
let j = false;
|
||||
|
||||
for (const result of results) {
|
||||
const questions = await apiQuestionToFetchedQuestions(result);
|
||||
// console.log(questions)
|
||||
for (const question of questions) {
|
||||
console.log(`- ${question.title}`);
|
||||
console.log(`- ${
|
||||
question.title
|
||||
}`);
|
||||
if ((! j && i % 20 === 0) || opts.args ?. debug) {
|
||||
console.log(question);
|
||||
j = true;
|
||||
|
@ -167,20 +189,16 @@ export const metaculus: Platform<"id" | "debug"> = {
|
|||
i += 1;
|
||||
}
|
||||
|
||||
return {
|
||||
questions: allQuestions,
|
||||
partial: false,
|
||||
};
|
||||
return {questions: allQuestions, partial: false};
|
||||
},
|
||||
|
||||
calculateStars(data) {
|
||||
const {numforecasts} = data.qualityindicators;
|
||||
const nuno = () =>
|
||||
(numforecasts || 0) > 300 ? 4 : (numforecasts || 0) > 100 ? 3 : 2;
|
||||
const nuno = () => (numforecasts || 0) > 300 ? 4 : (numforecasts || 0) > 100 ? 3 : 2;
|
||||
const eli = () => 3;
|
||||
const misha = () => 3;
|
||||
const starsDecimal = average([nuno(), eli(), misha()]);
|
||||
const starsInteger = Math.round(starsDecimal);
|
||||
return starsInteger;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user