Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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