This commit is contained in:
11
src/lib/SessionWrapper.tsx
Normal file
11
src/lib/SessionWrapper.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
|
||||
export default function SessionWrapper({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return <SessionProvider>{children}</SessionProvider>;
|
||||
}
|
||||
11
src/lib/actions.ts
Normal file
11
src/lib/actions.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
"use server";
|
||||
|
||||
import { UserController } from "./db";
|
||||
|
||||
export async function loginAction(formData: FormData) {
|
||||
const username = formData.get("username")?.toString();
|
||||
const password = formData.get("password")?.toString();
|
||||
|
||||
|
||||
if (username && password) await UserController.createUser(username, password);
|
||||
}
|
||||
63
src/lib/ai.ts
Normal file
63
src/lib/ai.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { format } from "util";
|
||||
|
||||
async function callZhipuAPI(
|
||||
messages: { role: string; content: string }[],
|
||||
model = "glm-4.6",
|
||||
) {
|
||||
const url = "https://open.bigmodel.cn/api/paas/v4/chat/completions";
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: "Bearer " + process.env.ZHIPU_API_KEY,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: model,
|
||||
messages: messages,
|
||||
temperature: 0.2,
|
||||
thinking: {
|
||||
type: "disabled",
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API 调用失败: ${response.status}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function getLLMAnswer(prompt: string) {
|
||||
return (
|
||||
await callZhipuAPI([
|
||||
{
|
||||
role: "user",
|
||||
content: prompt,
|
||||
},
|
||||
])
|
||||
).choices[0].message.content.trim() as string;
|
||||
}
|
||||
|
||||
export async function simpleGetLLMAnswer(
|
||||
prompt: string,
|
||||
searchParams: URLSearchParams,
|
||||
args: string[],
|
||||
) {
|
||||
if (args.some((arg) => typeof searchParams.get(arg) !== "string")) {
|
||||
return Response.json({
|
||||
status: "error",
|
||||
message: "Missing required parameters",
|
||||
});
|
||||
}
|
||||
return Response.json({
|
||||
status: "success",
|
||||
message: await getLLMAnswer(
|
||||
format(
|
||||
prompt,
|
||||
...args.map((v) => searchParams.get(v)),
|
||||
),
|
||||
),
|
||||
});
|
||||
}
|
||||
116
src/lib/db.ts
116
src/lib/db.ts
@@ -24,14 +24,126 @@ export class UserController {
|
||||
}
|
||||
static async getUserByUsername(username: string) {
|
||||
try {
|
||||
const user = await pool.query("SELECT * FROM users WHERE username = $1", [username]);
|
||||
const user = await pool.query("SELECT * FROM users WHERE username = $1", [
|
||||
username,
|
||||
]);
|
||||
return user.rows[0];
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
static async deleteUserById(id: number) {
|
||||
try {
|
||||
await pool.query("DELETE FROM users WHERE id = $1", [id]);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class FolderController {
|
||||
|
||||
static async getFolderById(id: number) {
|
||||
try {
|
||||
const folder = await pool.query("SELECT * FROM folders WHERE id = $1", [
|
||||
id,
|
||||
]);
|
||||
return folder.rows[0];
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
static async deleteFolderById(id: number) {
|
||||
try {
|
||||
await pool.query("DELETE FROM folders WHERE id = $1", [id]);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
static async getFoldersByOwner(owner: string) {
|
||||
try {
|
||||
const folders = await pool.query(
|
||||
"SELECT * FROM folders WHERE owner = $1",
|
||||
[owner],
|
||||
);
|
||||
return folders.rows;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
static async createFolder(name: string, owner: string) {
|
||||
try {
|
||||
return (
|
||||
await pool.query("INSERT INTO folders (name, owner) VALUES ($1, $2)", [
|
||||
name,
|
||||
owner,
|
||||
])
|
||||
).rows[0];
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class WordPairController {
|
||||
static async createWordPair(
|
||||
locale1: string,
|
||||
locale2: string,
|
||||
text1: string,
|
||||
text2: string,
|
||||
folderId: number,
|
||||
) {
|
||||
try {
|
||||
await pool.query(
|
||||
"INSERT INTO word_pairs (locale1, locale2, text1, text2, folder_id) VALUES ($1, $2, $3, $4, $5)",
|
||||
[locale1, locale2, text1, text2, folderId],
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
static async getWordPairById(id: number) {
|
||||
try {
|
||||
const wordPair = await pool.query(
|
||||
"SELECT * FROM word_pairs WHERE id = $1",
|
||||
[id],
|
||||
);
|
||||
return wordPair.rows[0];
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
static async deleteWordPairById(id: number) {
|
||||
try {
|
||||
await pool.query("DELETE FROM word_pairs WHERE id = $1", [id]);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
static async updateWordPairById(
|
||||
id: number,
|
||||
locale1: string,
|
||||
locale2: string,
|
||||
text1: string,
|
||||
text2: string,
|
||||
) {
|
||||
try {
|
||||
await pool.query(
|
||||
"UPDATE word_pairs SET locale1 = $1, locale2 = $2, text1 = $3, text2 = $4 WHERE id = $5",
|
||||
[locale1, locale2, text1, text2, id],
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
static async getWordPairsByFolderId(folderId: number) {
|
||||
try {
|
||||
const wordPairs = await pool.query(
|
||||
"SELECT * FROM word_pairs WHERE folder_id = $1",
|
||||
[folderId],
|
||||
);
|
||||
return wordPairs.rows;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
src/lib/localStorageOperators.ts
Normal file
17
src/lib/localStorageOperators.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { TranslationHistoryArraySchema, TranslationHistorySchema } from "@/interfaces";
|
||||
import { getLocalStorageOperator } from "@/utils";
|
||||
import z from "zod";
|
||||
|
||||
const MAX_HISTORY_LENGTH = 50;
|
||||
|
||||
export const tlso = getLocalStorageOperator<typeof TranslationHistoryArraySchema>(
|
||||
"translator",
|
||||
TranslationHistoryArraySchema,
|
||||
);
|
||||
export const tlsoPush = (item: z.infer<typeof TranslationHistorySchema>) => {
|
||||
tlso.set(
|
||||
[...tlso.get(), item as z.infer<typeof TranslationHistorySchema>].slice(
|
||||
-MAX_HISTORY_LENGTH,
|
||||
),
|
||||
);
|
||||
};
|
||||
16
src/lib/tts.ts
Normal file
16
src/lib/tts.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ProsodyOptions } from "edge-tts-universal";
|
||||
import { EdgeTTS } from "edge-tts-universal/browser";
|
||||
|
||||
export async function getTTSAudioUrl(
|
||||
text: string,
|
||||
short_name: string,
|
||||
options: ProsodyOptions | undefined = undefined,
|
||||
) {
|
||||
const tts = new EdgeTTS(text, short_name, options);
|
||||
try {
|
||||
const result = await tts.synthesize();
|
||||
return URL.createObjectURL(result.audio);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user