feat: Add post language data to backend and API

This commit is contained in:
Essem 2023-09-22 01:29:33 +00:00 committed by Kainoa Kanter
parent 5b1cd11618
commit 4a7bad11c6
9 changed files with 74 additions and 4 deletions

View File

@ -4,6 +4,8 @@ Breaking changes are indecated by the :warning: icon.
## v1.0.5 (unreleased)
- Added `lang` parameter to `notes/create` and `notes/edit`.
### dev11
- :warning: `notes/translate` now requires credentials.

View File

@ -0,0 +1,11 @@
export class AddPostLang1695334243217 {
name = 'AddPostLang1695334243217'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "note" ADD "lang" character varying(10)`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "lang"`);
}
}

View File

@ -66,6 +66,12 @@ export class Note {
})
public text: string | null;
@Column("varchar", {
length: 10,
nullable: true,
})
public lang: string | null;
@Column("varchar", {
length: 256,
nullable: true,

View File

@ -199,8 +199,6 @@ export const NoteRepository = db.getRepository(Note).extend({
host,
);
const lang =
detectLanguage(`${note.cw ?? ""}\n${note.text ?? ""}`) ?? "unknown";
const reactionEmoji = await populateEmojis(reactionEmojiNames, host);
const packed: Packed<"Note"> = await awaitAll({
id: note.id,
@ -260,7 +258,7 @@ export const NoteRepository = db.getRepository(Note).extend({
: undefined,
}
: {}),
lang: lang,
lang: note.lang,
});
if (packed.user.isCat && packed.user.speakAsCat && packed.text) {

View File

@ -53,6 +53,7 @@ import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js";
import { truncate } from "@/misc/truncate.js";
import { type Size, getEmojiSize } from "@/misc/emoji-meta.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
import { langmap } from "@/misc/langmap.js";
const logger = apLogger;
@ -305,11 +306,20 @@ export async function createNote(
// Text parsing
let text: string | null = null;
let lang: string | null = null;
if (
note.source?.mediaType === "text/x.misskeymarkdown" &&
typeof note.source?.content === "string"
) {
text = note.source.content;
if (note.contentMap != null) {
const key = Object.keys(note.contentMap)[0];
lang = Object.keys(langmap).includes(key) ? key : null;
}
} else if (note.contentMap != null) {
const entry = Object.entries(note.contentMap)[0];
lang = Object.keys(langmap).includes(entry[0]) ? entry[0] : null;
text = htmlToMfm(entry[1], note.tag);
} else if (typeof note.content === "string") {
text = htmlToMfm(note.content, note.tag);
}
@ -378,6 +388,7 @@ export async function createNote(
name: note.name,
cw,
text,
lang,
localOnly: false,
visibility,
visibleUsers,
@ -565,11 +576,20 @@ export async function updateNote(value: string | IObject, resolver?: Resolver) {
// Text parsing
let text: string | null = null;
let lang: string | null = null;
if (
post.source?.mediaType === "text/x.misskeymarkdown" &&
typeof post.source?.content === "string"
) {
text = post.source.content;
if (post.contentMap != null) {
const key = Object.keys(post.contentMap)[0];
lang = Object.keys(langmap).includes(key) ? key : null;
}
} else if (post.contentMap != null) {
const entry = Object.entries(post.contentMap)[0];
lang = Object.keys(langmap).includes(entry[0]) ? entry[0] : null;
text = htmlToMfm(entry[1], post.tag);
} else if (typeof post.content === "string") {
text = htmlToMfm(post.content, post.tag);
}
@ -663,6 +683,9 @@ export async function updateNote(value: string | IObject, resolver?: Resolver) {
if (text && text !== note.text) {
update.text = text;
}
if (lang && lang !== note.lang) {
update.lang = lang;
}
if (cw !== note.cw) {
update.cw = cw ? cw : null;
}

View File

@ -115,7 +115,7 @@ export default async function renderNote(
}),
);
const lang = detectLanguage(text);
const lang = note.lang ?? detectLanguage(text);
const contentMap = lang ? {
[lang]: content
} : null;

View File

@ -108,6 +108,7 @@ export const paramDef = {
},
},
text: { type: "string", maxLength: MAX_NOTE_TEXT_LENGTH, nullable: true },
lang: { type: "string", nullable: true, maxLength: 10 },
cw: { type: "string", nullable: true, maxLength: 100 },
localOnly: { type: "boolean", default: false },
noExtractMentions: { type: "boolean", default: false },
@ -294,6 +295,7 @@ export default define(meta, paramDef, async (ps, user) => {
}
: undefined,
text: ps.text || undefined,
lang: ps.lang,
reply,
renote,
cw: ps.cw,

View File

@ -35,6 +35,8 @@ import renderUpdate from "@/remote/activitypub/renderer/update.js";
import { deliverToRelays } from "@/services/relay.js";
// import { deliverQuestionUpdate } from "@/services/note/polls/update.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
import { detect as detectLanguage } from "tinyld";
import { langmap } from "@/misc/langmap.js";
export const meta = {
tags: ["notes"],
@ -169,6 +171,7 @@ export const paramDef = {
},
},
text: { type: "string", maxLength: MAX_NOTE_TEXT_LENGTH, nullable: true },
lang: { type: "string", nullable: true, maxLength: 10 },
cw: { type: "string", nullable: true, maxLength: 250 },
localOnly: { type: "boolean", default: false },
noExtractMentions: { type: "boolean", default: false },
@ -375,6 +378,15 @@ export default define(meta, paramDef, async (ps, user) => {
ps.text = null;
}
if (ps.lang) {
ps.lang = ps.lang.trim();
if (!Object.keys(langmap).includes(ps.lang.trim())) throw new Error("invalid param");
} else if (ps.text) {
ps.lang = detectLanguage(ps.text);
} else {
ps.lang = null;
}
let tags = [];
let emojis = [];
let mentionedUsers = [];
@ -532,6 +544,9 @@ export default define(meta, paramDef, async (ps, user) => {
if (ps.text !== note.text) {
update.text = ps.text;
}
if (ps.lang !== note.lang) {
update.lang = ps.lang;
}
if (ps.cw !== note.cw || (ps.cw && !note.cw)) {
update.cw = ps.cw;
}

View File

@ -67,6 +67,8 @@ import { shouldSilenceInstance } from "@/misc/should-block-instance.js";
import meilisearch from "../../db/meilisearch.js";
import { redisClient } from "@/db/redis.js";
import { Mutex } from "redis-semaphore";
import { detect as detectLanguage } from "tinyld";
import { langmap } from "@/misc/langmap.js";
const mutedWordsCache = new Cache<
{ userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[]
@ -139,6 +141,7 @@ type Option = {
createdAt?: Date | null;
name?: string | null;
text?: string | null;
lang?: string | null;
reply?: Note | null;
renote?: Note | null;
files?: DriveFile[] | null;
@ -276,6 +279,15 @@ export default async (
data.text = null;
}
if (data.lang) {
data.lang = data.lang.trim();
if (!Object.keys(langmap).includes(data.lang.trim())) throw new Error("invalid param");
} else if (data.text) {
data.lang = detectLanguage(data.text);
} else {
data.lang = null;
}
let tags = data.apHashtags;
let emojis = data.apEmojis;
let mentionedUsers = data.apMentions;
@ -712,6 +724,7 @@ async function insertNote(
: null,
name: data.name,
text: data.text,
lang: data.lang,
hasPoll: data.poll != null,
cw: data.cw == null ? null : data.cw,
tags: tags.map((tag) => normalizeForSearch(tag)),