Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ COPY federation/package.json /app/federation/package.json
COPY graphql/deno.json /app/graphql/deno.json
COPY models/deno.json /app/models/deno.json
COPY models/package.json /app/models/package.json
COPY runtime/deno.json /app/runtime/deno.json
COPY runtime/package.json /app/runtime/package.json
COPY web/deno.json /app/web/deno.json
COPY web-next/deno.jsonc /app/web-next/deno.jsonc
COPY web-next/package.json /app/web-next/package.json
Expand Down Expand Up @@ -82,6 +84,8 @@ COPY federation/package.json /app/federation/package.json
COPY graphql/deno.json /app/graphql/deno.json
COPY models/deno.json /app/models/deno.json
COPY models/package.json /app/models/package.json
COPY runtime/deno.json /app/runtime/deno.json
COPY runtime/package.json /app/runtime/package.json
COPY web/deno.json /app/web/deno.json
COPY web-next/deno.jsonc /app/web-next/deno.jsonc
COPY web-next/package.json /app/web-next/package.json
Expand Down
15 changes: 8 additions & 7 deletions ai/moderation.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { generateObject, jsonSchema } from "ai";
import { generateObject, jsonSchema, type LanguageModel } from "ai";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import type { CocProvision } from "@hackerspub/models/coc";
import type {
ModerationAnalysis,
ModerationAnalysisMatch,
ModerationAnalysisOptions,
ModerationAnalysisOptions as ApplicationModerationAnalysisOptions,
} from "@hackerspub/models/services";

export type ModerationProvision = CocProvision;
export type {
ModerationAnalysis,
ModerationAnalysisMatch,
ModerationAnalysisOptions,
};
export type { ModerationAnalysis, ModerationAnalysisMatch };

export interface ModerationAnalysisOptions
extends Omit<ApplicationModerationAnalysisOptions, "model"> {
model: LanguageModel;
}

const ANALYSIS_SCHEMA = jsonSchema<ModerationAnalysis>({
type: "object",
Expand Down
30 changes: 27 additions & 3 deletions ai/services.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
import type { AiServices } from "@hackerspub/models/services";
import type { LanguageModel } from "ai";
import { analyzeFlaggedContent } from "./moderation.ts";
import { summarize } from "./summary.ts";
import { translate } from "./translate.ts";

function unwrapModel(
model: { readonly implementation: unknown },
): LanguageModel {
return model != null && "implementation" in model
? model.implementation as LanguageModel
: model as unknown as LanguageModel;
Comment thread
dahlia marked this conversation as resolved.
}

export const aiServices: AiServices = {
analyzeFlaggedContent,
summarize,
translate,
analyzeFlaggedContent: (options) =>
analyzeFlaggedContent({
...options,
model: unwrapModel(options.model),
}),
summarize: (options) =>
summarize({
...options,
model: unwrapModel(options.model),
}),
translate: (options) =>
translate({
...options,
model: unwrapModel(options.model),
summarizationModel: options.summarizationModel == null
? undefined
: unwrapModel(options.summarizationModel),
}),
};
10 changes: 7 additions & 3 deletions ai/summary.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { generateText } from "ai";
import { generateText, type LanguageModel } from "ai";
import { readdir, readFile } from "node:fs/promises";
import { join } from "node:path";
import {
findNearestLocale,
isLocale,
type Locale,
} from "@hackerspub/models/i18n";
import type { SummaryOptions } from "@hackerspub/models/services";
import type { SummaryOptions as ApplicationSummaryOptions } from "@hackerspub/models/services";
import { removeDetailsFromSummaryInput } from "@hackerspub/models/summary";

const PROMPT_LANGUAGES: Locale[] = (
Expand All @@ -16,6 +16,11 @@ const PROMPT_LANGUAGES: Locale[] = (
)
).map((f) => f.name.replace(/\.md$/, "")).filter(isLocale);

export interface SummaryOptions
extends Omit<ApplicationSummaryOptions, "model"> {
model: LanguageModel;
}

async function getSummaryPrompt(
sourceLanguage: string,
targetLanguage: string,
Expand All @@ -39,7 +44,6 @@ async function getSummaryPrompt(
}

export { removeDetailsFromSummaryInput };
export type { SummaryOptions };

export async function summarize(options: SummaryOptions): Promise<string> {
const system = await getSummaryPrompt(
Expand Down
14 changes: 11 additions & 3 deletions ai/translate.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { fetchWebPage } from "@vertana/context-web";
import type { ContextSource, RequiredContextSource } from "@vertana/core";
import { translate as vertanaTranslate } from "@vertana/facade";
import type { TranslationOptions } from "@hackerspub/models/services";
import type { LanguageModel } from "ai";
import type { TranslationOptions as ApplicationTranslationOptions } from "@hackerspub/models/services";

export type { TranslationOptions };
export interface TranslationOptions
extends Omit<ApplicationTranslationOptions, "model" | "summarizationModel"> {
model: LanguageModel;
summarizationModel?: LanguageModel;
}

/**
* Creates a required context source with author information
Expand Down Expand Up @@ -72,7 +77,10 @@ export async function translate(options: TranslationOptions): Promise<string> {
maxCharsPerPage: 10_000,
maxTotalChars: 30_000,
...(options.summarizationModel && {
summarize: { model: options.summarizationModel, maxChars: 3_000 },
summarize: {
model: options.summarizationModel,
maxChars: 3_000,
},
}),
}));

Expand Down
7 changes: 4 additions & 3 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"./federation",
"./graphql",
"./models",
"./runtime",
"./web",
"./web-next"
],
Expand Down Expand Up @@ -80,9 +81,9 @@
"@tailwindcss/typography": "npm:@tailwindcss/typography@^0.5.15",
"@types/fluent-ffmpeg": "npm:@types/fluent-ffmpeg@^2.1.27",
"@types/mdast": "npm:@types/mdast@^4.0.4",
"@upyo/core": "jsr:@upyo/core@^0.1.1",
"@upyo/mailgun": "jsr:@upyo/mailgun@^0.1.1",
"@upyo/mock": "jsr:@upyo/mock@^0.1.1",
"@upyo/core": "jsr:@upyo/core@^0.5.0",
"@upyo/mailgun": "jsr:@upyo/mailgun@^0.5.0",
"@upyo/mock": "jsr:@upyo/mock@^0.5.0",
"@valibot/valibot": "jsr:@valibot/valibot@^1.0.0",
"@vertana/context-web": "npm:@vertana/context-web@^0.2.0",
"@vertana/core": "jsr:@vertana/core@^0.2.0",
Expand Down
Loading
Loading