Skip to content

Commit

Permalink
Merge pull request #266 from ubiquity-os-marketplace/development
Browse files Browse the repository at this point in the history
Merge development into main
  • Loading branch information
gentlementlegen authored Feb 11, 2025
2 parents c6c2714 + cf0f266 commit 2fe8dd2
Show file tree
Hide file tree
Showing 30 changed files with 6,187 additions and 3,265 deletions.
6 changes: 5 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@
"pico",
"timespan",
"Retryable",
"ratelimit"
"ratelimit",
"laeiouy",
"Flesch",
"Kincaid",
"flesch"
],
"dictionaries": ["typescript", "node", "software-terms"],
"import": [
Expand Down
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @gentlementlegen
8 changes: 4 additions & 4 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"@supabase/supabase-js": "2.42.0",
"@ubiquity-dao/rpc-handler": "1.3.0",
"@ubiquity-os/permit-generation": "^2.0.6",
"@ubiquity-os/plugin-sdk": "^2.0.2",
"@ubiquity-os/ubiquity-os-logger": "^1.3.2",
"@ubiquity-os/plugin-sdk": "^2.0.6",
"@ubiquity-os/ubiquity-os-logger": "^1.4.0",
"decimal.js": "10.4.3",
"ethers": "^5.7.2",
"js-tiktoken": "1.0.15",
Expand Down Expand Up @@ -808,9 +808,9 @@

"@ubiquity-os/permit-generation": ["@ubiquity-os/[email protected]", "", { "dependencies": { "@actions/core": "^1.10.1", "@actions/github": "^6.0.0", "@octokit/rest": "^20.1.0", "@octokit/webhooks": "^13.3.0", "@sinclair/typebox": "^0.32.5", "@supabase/supabase-js": "2.42.0", "@ubiquity-dao/rpc-handler": "1.3.0", "@uniswap/permit2-sdk": "^1.2.0", "dotenv": "^16.4.4", "ethers": "^5.7.2", "libsodium-wrappers": "^0.7.13" } }, "sha512-NnBijxuwdM6vIS1oU6lZg2Ke1GGSaLtm+hqGgzbpyeO/IkzinWTWEuN7nMKIMvES98ZwUSz13NOOWexSUcN4MQ=="],

"@ubiquity-os/plugin-sdk": ["@ubiquity-os/[email protected].2", "", { "dependencies": { "@actions/core": "^1.11.1", "@actions/github": "^6.0.0", "@octokit/core": "^6.1.2", "@octokit/plugin-paginate-graphql": "^5.2.4", "@octokit/plugin-paginate-rest": "^11.3.5", "@octokit/plugin-rest-endpoint-methods": "^13.2.6", "@octokit/plugin-retry": "^7.1.2", "@octokit/plugin-throttling": "^9.3.2", "@octokit/rest": "^21.0.2", "@octokit/types": "^13.6.1", "@octokit/webhooks": "^13.3.0", "@ubiquity-os/ubiquity-os-logger": "^1.3.2", "dotenv": "^16.4.5", "hono": "^4.6.9" }, "peerDependencies": { "@sinclair/typebox": "0.34.3" } }, "sha512-Pdxl64w8ZSWovzvSfoDWdohpjr93gZ2eMTo18PSt164kB/r5JMsMSni/WV9duxxKoscpinfxcws2zOebPpXS3A=="],
"@ubiquity-os/plugin-sdk": ["@ubiquity-os/[email protected].6", "", { "dependencies": { "@actions/core": "^1.11.1", "@actions/github": "^6.0.0", "@octokit/core": "^6.1.2", "@octokit/plugin-paginate-graphql": "^5.2.4", "@octokit/plugin-paginate-rest": "^11.3.5", "@octokit/plugin-rest-endpoint-methods": "^13.2.6", "@octokit/plugin-retry": "^7.1.2", "@octokit/plugin-throttling": "^9.3.2", "@octokit/rest": "^21.0.2", "@octokit/types": "^13.6.1", "@octokit/webhooks": "^13.3.0", "@ubiquity-os/ubiquity-os-logger": "^1.4.0", "dotenv": "^16.4.5", "hono": "^4.6.9" }, "peerDependencies": { "@sinclair/typebox": "0.34.3" } }, "sha512-xXdmOBu6Oygr2DmAeUKtluJb3yGdLvLoPVhZEbrXLOOWpvsDU73b+GAsDyrQfGjE16ZBFeoZ0N9VChbvWU9GSA=="],

"@ubiquity-os/ubiquity-os-logger": ["@ubiquity-os/ubiquity-os-logger@1.3.2", "", {}, "sha512-oTIzR8z4jAQmaeJp98t1bZUKE3Ws9pas0sbxt58fC37MwXclPMWrLO+a0JlhPkdJYsvpv/q/79wC2MKVhOIVXQ=="],
"@ubiquity-os/ubiquity-os-logger": ["@ubiquity-os/ubiquity-os-logger@1.4.0", "", {}, "sha512-giybluPmu0sreEWi60t9X8NxC5d48X7oQAb9RjXR7wX/ZNYugbAaKgj0TYEqECvSVDqgzpKo7UNerh1UQBscGw=="],

"@uniswap/permit2-sdk": ["@uniswap/[email protected]", "", { "dependencies": { "ethers": "^5.7.0", "tiny-invariant": "^1.1.0" } }, "sha512-LstYQWP47dwpQrgqBJ+ysFstne9LgI5FGiKHc2ewjj91MTY8Mq1reocu6U/VDncdR5ef30TUOcZ7gPExRY8r6Q=="],

Expand Down
1 change: 0 additions & 1 deletion dist/33.index.js.map

This file was deleted.

4 changes: 2 additions & 2 deletions dist/index.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/index.js.map

This file was deleted.

1 change: 0 additions & 1 deletion dist/sourcemap-register.cjs

This file was deleted.

21 changes: 21 additions & 0 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,27 @@
"default": {},
"type": "object",
"properties": {
"readabilityScoring": {
"default": {},
"type": "object",
"properties": {
"enabled": {
"default": true,
"description": "Enable Flesch-Kincaid readability scoring",
"type": "boolean"
},
"weight": {
"default": 0.3,
"description": "Weight of readability score in the total formatting score",
"type": "number"
},
"targetReadabilityScore": {
"default": 60,
"description": "Ideal Flesch-Kincaid score (60-70 is considered ideal for general audience)",
"type": "number"
}
}
},
"multipliers": {
"description": "Multipliers applied to different parts of the comment according the role of the author",
"default": [
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
"@supabase/supabase-js": "2.42.0",
"@ubiquity-dao/rpc-handler": "1.3.0",
"@ubiquity-os/permit-generation": "^2.0.6",
"@ubiquity-os/plugin-sdk": "^2.0.2",
"@ubiquity-os/ubiquity-os-logger": "^1.3.2",
"@ubiquity-os/plugin-sdk": "^2.0.6",
"@ubiquity-os/ubiquity-os-logger": "^1.4.0",
"decimal.js": "10.4.3",
"ethers": "^5.7.2",
"js-tiktoken": "1.0.15",
Expand Down
20 changes: 20 additions & 0 deletions src/configuration/formatting-evaluator-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,26 @@ const rewardsType = Type.Object(

export const formattingEvaluatorConfigurationType = Type.Object(
{
/**
* Configuration for readability scoring using Flesch-Kincaid
*/
readabilityScoring: Type.Object(
{
enabled: Type.Boolean({
default: true,
description: "Enable Flesch-Kincaid readability scoring",
}),
weight: Type.Number({
default: 0.3,
description: "Weight of readability score in the total formatting score",
}),
targetReadabilityScore: Type.Number({
default: 60,
description: "Ideal Flesch-Kincaid score (60-70 is considered ideal for general audience)",
}),
},
{ default: {} }
),
/**
* Multipliers applied to different parts of the comment body content
*/
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function isCollaboratorRole(role: string) {
return COLLABORATOR_ROLES.includes(role.toLowerCase());
}

export async function isUserAllowedToGeneratePermits(context: ContextPlugin) {
export async function isUserAllowedToGenerateRewards(context: ContextPlugin) {
const { octokit, payload } = context;
const username = payload.sender.login;
try {
Expand Down
71 changes: 65 additions & 6 deletions src/parser/formatting-evaluator-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from "../configuration/formatting-evaluator-config";
import { IssueActivity } from "../issue-activity";
import { BaseModule } from "../types/module";
import { GithubCommentScore, Result, WordResult } from "../types/results";
import { GithubCommentScore, ReadabilityScore, Result, WordResult } from "../types/results";
import { typeReplacer } from "../helpers/result-replacer";
import { ContextPlugin } from "../types/plugin-input";
import { parsePriorityLabel } from "../helpers/github";
Expand All @@ -28,6 +28,7 @@ export class FormattingEvaluatorModule extends BaseModule {
private readonly _md = new MarkdownIt();
private readonly _multipliers: { [k: number]: Multiplier } = {};
private readonly _wordCountExponent: number;
private readonly _readabilityConfig: FormattingEvaluatorConfiguration["readabilityScoring"];

_getEnumValue(key: CommentType) {
let res = 0;
Expand All @@ -40,6 +41,11 @@ export class FormattingEvaluatorModule extends BaseModule {

constructor(context: ContextPlugin) {
super(context);
this._readabilityConfig = this._configuration?.readabilityScoring ?? {
enabled: true,
weight: 0.3,
targetReadabilityScore: 60,
};
if (this._configuration?.multipliers) {
this._multipliers = this._configuration.multipliers.reduce((acc, curr) => {
return {
Expand All @@ -61,14 +67,57 @@ export class FormattingEvaluatorModule extends BaseModule {
this._wordCountExponent = this._configuration?.wordCountExponent ?? 0.85;
}

private _countSyllables(word: string): number {
word = word.toLowerCase();
if (word.length <= 3) return 1;

word = word.replace(/(?:[^laeiouy]es|ed|[^laeiouy]e)$/, "");
word = word.replace(/^y/, "");
const syllables = word.match(/[aeiouy]{1,2}/g);
return syllables ? syllables.length : 1;
}

private _calculateFleschKincaid(text: string): ReadabilityScore {
const sentences = text.split(/[.!?]+/).filter((s) => s.trim().length > 0).length ?? 1;
const words = text.match(new RegExp(wordRegex, "g")) ?? [];
const wordCount = words.length ?? 1;
const syllableCount = words.reduce((count, word) => count + this._countSyllables(word), 0);
const wordsPerSentence = wordCount / Math.max(1, sentences);
const syllablesPerWord = syllableCount / Math.max(1, wordCount);
const fleschKincaid = sentences && wordCount ? 206.835 - 1.015 * wordsPerSentence - 84.6 * syllablesPerWord : 0;

// Normalize score between 0 and 1
let normalizedScore: number;
if (fleschKincaid > 100) {
normalizedScore = 1.0;
} else if (fleschKincaid <= 0) {
normalizedScore = 0.0;
} else {
const distance = Math.abs(fleschKincaid - (this._readabilityConfig?.targetReadabilityScore ?? 60));
normalizedScore = Math.max(0, Math.min(1, (100 - distance) / 100));
}

return {
fleschKincaid,
syllables: syllableCount,
sentences,
score: normalizedScore,
};
}

async transform(data: Readonly<IssueActivity>, result: Result) {
for (const key of Object.keys(result)) {
const currentElement = result[key];
const comments = currentElement.comments || [];
const comments = currentElement.comments ?? [];
for (const comment of comments) {
const { formatting, words } = this._getFormattingScore(comment);
const { formatting, words, readability } = this._getFormattingScore(comment);
const multiplierFactor = this._multipliers?.[comment.type] ?? { multiplier: 0 };
const formattingTotal = this._calculateFormattingTotal(formatting, words, multiplierFactor).toDecimalPlaces(2);
const formattingTotal = this._calculateFormattingTotal(
formatting,
words,
multiplierFactor,
readability
).toDecimalPlaces(2);
const priority = parsePriorityLabel(data.self?.labels);
const reward = (comment.score?.reward ? formattingTotal.add(comment.score.reward) : formattingTotal).toNumber();
comment.score = {
Expand All @@ -80,6 +129,7 @@ export class FormattingEvaluatorModule extends BaseModule {
},
priority: priority,
words,
readability,
multiplier: multiplierFactor.multiplier,
};
}
Expand All @@ -90,7 +140,8 @@ export class FormattingEvaluatorModule extends BaseModule {
private _calculateFormattingTotal(
formatting: ReturnType<typeof this._getFormattingScore>["formatting"],
regex: WordResult,
multiplierFactor: Multiplier
multiplierFactor: Multiplier,
readability?: ReadabilityScore
): Decimal {
if (!formatting) return new Decimal(0);

Expand All @@ -102,6 +153,13 @@ export class FormattingEvaluatorModule extends BaseModule {
});

sum = sum.add(new Decimal(regex.result));

// Apply readability scoring if enabled
if (this._readabilityConfig.enabled && readability) {
const readabilityScore = new Decimal(readability.score).mul(this._readabilityConfig.weight).mul(sum);
sum = sum.add(readabilityScore);
}

return sum.mul(multiplierFactor.multiplier);
}

Expand All @@ -120,7 +178,8 @@ export class FormattingEvaluatorModule extends BaseModule {
const temp = new JSDOM(html);
if (temp.window.document.body) {
const res = this._classifyTagsWithWordCount(temp.window.document.body, comment.type);
return { formatting: res.formatting, words: res.words };
const readability = this._calculateFleschKincaid(temp.window.document.body.textContent ?? "");
return { formatting: res.formatting, words: res.words, readability };
} else {
throw new Error(`Could not create DOM for comment [${JSON.stringify(comment)}]`);
}
Expand Down
3 changes: 2 additions & 1 deletion src/parser/review-incentivizer-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export class ReviewIncentivizerModule extends BaseModule {

const prNumbers = data.linkedReviews.map((review) => review.self?.number);
if (!prNumbers.length) {
throw this.context.logger.error(`No pull request linked to this issue, Aborting`);
this.context.logger.warn(`No pull request is linked to this issue, won't run review incentivizer`);
return result;
}

const message =
Expand Down
9 changes: 6 additions & 3 deletions src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Processor } from "./parser/processor";
import { parseGitHubUrl } from "./start";
import { ContextPlugin } from "./types/plugin-input";
import { Result } from "./types/results";
import { isUserAllowedToGeneratePermits } from "./helpers/permissions";
import { isUserAllowedToGenerateRewards } from "./helpers/permissions";

export async function run(context: ContextPlugin) {
const { eventName, payload, logger, config } = context;
Expand All @@ -25,8 +25,11 @@ export async function run(context: ContextPlugin) {
return result.logMessage.raw;
}

if (config.incentives.collaboratorOnlyPaymentInvocation && !(await isUserAllowedToGeneratePermits(context))) {
const result = logger.error("You are not allowed to generate permits.");
if (config.incentives.collaboratorOnlyPaymentInvocation && !(await isUserAllowedToGenerateRewards(context))) {
const result =
payload.sender.type === "Bot"
? logger.warn("Bots can not generate rewards.")
: logger.error("You are not allowed to generate rewards.");
await postComment(context, result);
return result.logMessage.raw;
}
Expand Down
8 changes: 8 additions & 0 deletions src/types/results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ export interface WordResult {
result: number;
}

export interface ReadabilityScore {
fleschKincaid: number;
syllables: number;
sentences: number;
score: number;
}

export interface ReviewScore {
priority: number;
reviewId: number;
Expand All @@ -48,6 +55,7 @@ export interface GithubCommentScore {
result: number;
};
words?: WordResult;
readability?: ReadabilityScore;
multiplier: number;
relevance?: number;
clarity?: number;
Expand Down
Loading

0 comments on commit 2fe8dd2

Please sign in to comment.