Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

全体のリファクタ #135

Merged
merged 3 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
DialogHeader,
DialogTitle,
} from "~/components/ui/dialog";
import { GoogleForm } from "./google-form";
import { GoogleForm } from "../routes/resources+/google-form";

interface LoginDialogProps {
isOpen: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function AIModelSelector({ onModelSelect }: AIModelSelectorProps) {

return (
<Select value={selectedModel} onValueChange={handleModelChange}>
<SelectTrigger className="w-[200px]">
<SelectTrigger>
<SelectValue placeholder="Select a model" />
</SelectTrigger>
<SelectContent>
Expand Down
1 change: 0 additions & 1 deletion web/app/feature/translate/utils/addNumbersToContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export function shouldProcessElement(element: Element): boolean {
"style",
"textarea",
"input",
"pre",
"noscript",
"iframe",
"source",
Expand Down
5 changes: 0 additions & 5 deletions web/app/feature/translate/utils/extractArticle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,5 @@ export const extractArticle = (

const resolvedContent = contentDom.serialize();

console.log("article", {
...article,
content: resolvedContent,
});

return { content: resolvedContent, title: article.title };
};
22 changes: 19 additions & 3 deletions web/app/feature/translate/utils/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ export async function getGeminiModelResponse(
console.error("Max retries reached. Translation failed.");
throw lastError || new Error("Translation failed after max retries");
}
export async function validateGeminiApiKey(apiKey: string): Promise<boolean> {
export async function validateGeminiApiKey(
apiKey: string,
): Promise<{ isValid: boolean; errorMessage?: string }> {
try {
const genAI = new GoogleGenerativeAI(apiKey);
const model = genAI.getGenerativeModel({ model: "gemini-pro" });
Expand All @@ -90,9 +92,23 @@ export async function validateGeminiApiKey(apiKey: string): Promise<boolean> {
const response = await result.response;
const text = response.text();

return text.length > 0;
return { isValid: text.length > 0 };
} catch (error) {
console.error("Gemini API key validation failed:", error);
return false;
if (
error instanceof Error &&
error.message.includes("The model is overloaded")
) {
return {
isValid: false,
errorMessage:
"The model is currently overloaded. Please try again later.",
};
}
return {
isValid: false,
errorMessage:
"Failed to validate the API key. Please check your key and try again.",
};
}
}
2 changes: 1 addition & 1 deletion web/app/routes/reader.$/components/AddTranslationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { getZodConstraint } from "@conform-to/zod";
import { useFetcher } from "@remix-run/react";
import { Save } from "lucide-react";
import { useState } from "react";
import { LoginDialog } from "~/components/LoginDialog";
import { Button } from "~/components/ui/button";
import { Textarea } from "~/components/ui/textarea";
import { LoginDialog } from "~/routes/resources+/LoginDialog";
import type { action } from "../route";
import { addTranslationSchema } from "../types";

Expand Down
2 changes: 1 addition & 1 deletion web/app/routes/reader.$/components/VoteButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { parseWithZod } from "@conform-to/zod";
import { useFetcher } from "@remix-run/react";
import { memo, useMemo } from "react";
import { useState } from "react";
import { LoginDialog } from "~/routes/resources+/LoginDialog";
import { LoginDialog } from "~/components/LoginDialog";
import { cn } from "~/utils/cn";
import type { TranslationWithVote } from "../types";
import { voteSchema } from "../types";
Expand Down
9 changes: 4 additions & 5 deletions web/app/routes/reader.$/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { fetchLatestPageVersionWithTranslations } from "./functions/queries.serv
import { actionSchema } from "./types";

export const loader = async ({ params, request }: LoaderFunctionArgs) => {
const targetLanguage = await getTargetLanguage(request);
const { "*": urlParam } = params;

if (!urlParam) {
Expand All @@ -24,6 +23,7 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {

const safeUser = await authenticator.isAuthenticated(request);
const safeUserId = safeUser?.id;
const targetLanguage = await getTargetLanguage(request);
const normalizedUrl = normalizeAndSanitizeUrl(urlParam);
const pageData = await fetchLatestPageVersionWithTranslations(
normalizedUrl,
Expand Down Expand Up @@ -78,15 +78,14 @@ export const action = async ({ request }: ActionFunctionArgs) => {
};

export default function ReaderView() {
const { encodedUrl } = useParams();
const { targetLanguage, pageData, safeUser } =
useTypedLoaderData<typeof loader>();
const { "*": urlParam } = useParams();
const { pageData, safeUser } = useTypedLoaderData<typeof loader>();

if (!pageData) {
return <div>Loading...</div>;
}

const originalUrl = encodedUrl ? decodeURIComponent(encodedUrl) : "";
const originalUrl = urlParam ? decodeURIComponent(urlParam) : "";

return (
<div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,54 @@
import { useForm } from "@conform-to/react";
import { getFormProps, getInputProps } from "@conform-to/react";
import { getZodConstraint, parseWithZod } from "@conform-to/zod";
import { Form, useActionData } from "@remix-run/react";
import type { ActionFunctionArgs } from "@remix-run/node";
import { Link } from "@remix-run/react";
import { useNavigation } from "@remix-run/react";
import { useFetcher } from "@remix-run/react";
import { Save } from "lucide-react";
import { ExternalLink, Key } from "lucide-react";
import { TriangleAlert } from "lucide-react";
import { z } from "zod";
import { LoadingSpinner } from "~/components/LoadingSpinner";
import { Alert, AlertDescription } from "~/components/ui/alert";
import { Button } from "~/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { Input } from "~/components/ui/input";
import type { action } from "../route";
import { geminiApiKeySchema } from "../types";
import { validateGeminiApiKey } from "~/feature/translate/utils/gemini";
import { authenticator } from "~/utils/auth.server";
import { updateGeminiApiKey } from "./functions/mutations.server";

export const geminiApiKeySchema = z.object({
geminiApiKey: z.string().min(1, "API key is required"),
});

export async function action({ request }: ActionFunctionArgs) {
const safeUser = await authenticator.isAuthenticated(request, {
failureRedirect: "/",
});
const submission = parseWithZod(await request.formData(), {
schema: geminiApiKeySchema,
});
if (submission.status !== "success") {
return { lastResult: submission.reply() };
}

const { isValid, errorMessage } = await validateGeminiApiKey(
submission.value.geminiApiKey,
);
if (!isValid) {
return {
lastResult: submission.reply({
formErrors: [errorMessage || "Gemini API key validation failed"],
}),
};
}
await updateGeminiApiKey(safeUser.id, submission.value.geminiApiKey);
return { lastResult: submission.reply({ resetForm: true }) };
}

export function GeminiApiKeyForm() {
const actionData = useActionData<typeof action>();
const navigation = useNavigation();
const fetcher = useFetcher<typeof action>();
const actionData = fetcher.data;
const [form, { geminiApiKey }] = useForm({
id: "gemini-api-key-form",
lastResult: actionData?.lastResult,
Expand Down Expand Up @@ -71,7 +102,11 @@ export function GeminiApiKeyForm() {
</AlertDescription>
</div>
</Alert>
<Form method="post" {...getFormProps(form)}>
<fetcher.Form
method="post"
action="/resources/gemini-api-key-form"
{...getFormProps(form)}
>
<div className="flex items-center">
<div className="w-full">
<Input
Expand All @@ -85,12 +120,10 @@ export function GeminiApiKeyForm() {
</div>
<Button
type="submit"
name="intent"
value="saveGeminiApiKey"
size="icon"
disabled={navigation.state === "submitting"}
disabled={fetcher.state === "submitting"}
>
{navigation.state === "submitting" ? (
{fetcher.state === "submitting" ? (
<LoadingSpinner />
) : (
<Save className="w-4 h-4" />
Expand All @@ -107,7 +140,7 @@ export function GeminiApiKeyForm() {
{form.errors && (
<p className="text-red-500 text-center mt-2">{form.errors}</p>
)}
</Form>
</fetcher.Form>
</CardContent>
</Card>
);
Expand Down
9 changes: 5 additions & 4 deletions web/app/routes/resources+/google-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { FcGoogle } from "react-icons/fc";
import { Button } from "~/components/ui/button";
import { authenticator } from "~/utils/auth.server";

export const action = async ({ request }: ActionFunctionArgs) => {
export async function action({ request }: ActionFunctionArgs) {
return authenticator.authenticate("google", request, {
successRedirect: "/api/auth/callback/google",
failureRedirect: "/login",
});
};
export const GoogleForm = ({ redirectTo }: { redirectTo: string }) => {
}

export function GoogleForm({ redirectTo }: { redirectTo: string }) {
const fetcher = useFetcher();
return (
<fetcher.Form
Expand All @@ -31,4 +32,4 @@ export const GoogleForm = ({ redirectTo }: { redirectTo: string }) => {
</Button>
</fetcher.Form>
);
};
}
15 changes: 6 additions & 9 deletions web/app/routes/translate/components/URLTranslationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { LoadingSpinner } from "~/components/LoadingSpinner";
import { Alert, AlertDescription, AlertTitle } from "~/components/ui/alert";
import { Button } from "~/components/ui/button";
import { Input } from "~/components/ui/input";
import { AIModelSelector } from "~/feature/translate/components/AIModelSelector";
import type { action } from "../route";
import { urlTranslationSchema } from "../types";
import { AIModelSelector } from "./AIModelSelector";

export function URLTranslationForm() {
const navigation = useNavigation();
Expand Down Expand Up @@ -39,14 +39,11 @@ export function URLTranslationForm() {
/>
<div id={fields.url.errorId}>{fields.url.errors}</div>
</div>
<AIModelSelector onModelSelect={setSelectedModel} />
<div className="w-[200px]">
<AIModelSelector onModelSelect={setSelectedModel} />
</div>
<input type="hidden" name="model" value={selectedModel} />
<Button
type="submit"
name="intent"
value="translateUrl"
disabled={navigation.state === "submitting"}
>
<Button type="submit" disabled={navigation.state === "submitting"}>
{navigation.state === "submitting" ? (
<LoadingSpinner />
) : (
Expand All @@ -55,7 +52,7 @@ export function URLTranslationForm() {
</Button>
</div>
</Form>
{actionData?.intent === "translateUrl" && actionData?.url && (
{actionData?.url && (
ttizze marked this conversation as resolved.
Show resolved Hide resolved
<Alert className="bg-blue-50 border-blue-200 text-blue-800 animate-in fade-in duration-300">
<AlertTitle className="text-center">
Translation Job Started
Expand Down
16 changes: 13 additions & 3 deletions web/app/routes/translate/components/UserAITranslationStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import { Link } from "@remix-run/react";
import { Form } from "@remix-run/react";
import { useNavigation } from "@remix-run/react";
import { RotateCcw } from "lucide-react";
import { useState } from "react";
import { LoadingSpinner } from "~/components/LoadingSpinner";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { Progress } from "~/components/ui/progress";
import { ScrollArea } from "~/components/ui/scroll-area";
import { AIModelSelector } from "~/feature/translate/components/AIModelSelector";
import { cn } from "~/utils/cn";
import type { UserAITranslationInfoItem } from "../types";
import { urlTranslationSchema } from "../types";

type UserAITranslationStatusProps = {
userAITranslationInfo: UserAITranslationInfoItem[];
targetLanguage: string;
Expand All @@ -22,6 +25,7 @@ export function UserAITranslationStatus({
userAITranslationInfo = [],
targetLanguage,
}: UserAITranslationStatusProps) {
const [selectedModel, setSelectedModel] = useState("gemini-1.5-flash");
const navigation = useNavigation();
const [form, fields] = useForm({
id: "url-re-translation-form",
Expand Down Expand Up @@ -99,17 +103,23 @@ export function UserAITranslationStatus({
name="url"
value={item.pageVersion.page.url}
/>
<div className="w-full">
<AIModelSelector onModelSelect={setSelectedModel} />
<input
type="hidden"
name="model"
value={selectedModel}
/>
</div>
ttizze marked this conversation as resolved.
Show resolved Hide resolved
<Button
type="submit"
Comment on lines +106 to 115

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

name="intent"value="translateUrl"が削除されていますが、これが意図的な変更であるか確認してください。もし必要であれば、以下のように修正してください。

+ 														name="intent"
+ 														value="translateUrl"

name="intent"
value="translateUrl"
className="w-full"
disabled={navigation.state === "submitting"}
>
{navigation.state === "submitting" ? (
<LoadingSpinner />
) : (
<RotateCcw className="w-4 h-4" />
<RotateCcw className="w-4 h-4 mr-2" />
)}
</Button>
</Form>
Expand Down
32 changes: 0 additions & 32 deletions web/app/routes/translate/functions/translate-job.server.ts

This file was deleted.

Loading
Loading