Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
orztv committed Oct 17, 2024
1 parent f63d61b commit 9f4b26d
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 22 deletions.
4 changes: 3 additions & 1 deletion app/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type Config = {
FLUX_NUM_STEPS: number;
CUSTOMER_MODEL_MAP: { [key: string]: string };
getme: string;
CHENGYU_WEBHOOK_URL?: string;
};

export function getConfig(env: any): Config {
Expand All @@ -34,5 +35,6 @@ export function getConfig(env: any): Config {
FLUX_NUM_STEPS: parseInt(env.FLUX_NUM_STEPS || "6", 10),
CUSTOMER_MODEL_MAP: JSON.parse(env.CUSTOMER_MODEL_MAP || "{}"),
getme: env.getme || "",
CHENGYU_WEBHOOK_URL: env.CHENGYU_WEBHOOK_URL || "",
};
}
}
37 changes: 27 additions & 10 deletions app/routes/_index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { json, type LoaderFunction } from "@remix-run/cloudflare";
import { useLoaderData } from "@remix-run/react";
import { useLoaderData, Link } from "@remix-run/react";
import { createAppContext } from "../context";
import { AppError } from "../utils/error";
import { Link } from "@remix-run/react";
import type { AppLoadContext } from "@remix-run/cloudflare";

export const loader: LoaderFunction = async ({ context }) => {
export const loader: LoaderFunction = async ({ context }: { context: AppLoadContext }) => {
console.log("Loader started");
const appContext = createAppContext(context);
const { imageGenerationService, config } = appContext;
Expand All @@ -30,47 +30,64 @@ export const loader: LoaderFunction = async ({ context }) => {
};

export default function Index() {
const { cfAiStatus, configStatus } = useLoaderData<typeof loader>();

return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-purple-600 via-pink-500 to-red-500">
<div className="bg-white bg-opacity-10 backdrop-filter backdrop-blur-lg rounded-3xl shadow-2xl p-10">
<h1 className="text-4xl font-extrabold text-white mb-8 text-center">CF Flux Remix</h1>
<div className="bg-white bg-opacity-10 backdrop-filter backdrop-blur-lg rounded-3xl shadow-2xl p-10 max-w-lg w-full">
<h1 className="text-5xl font-extrabold text-white mb-8 text-center">CF Flux Remix</h1>
<nav>
<ul className="space-y-4">
<li>
<Link
to="/generate-image"
className="block w-full text-center px-6 py-3 text-lg font-semibold text-white bg-gradient-to-r from-indigo-500 to-indigo-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-indigo-400"
className="block w-full text-center px-6 py-4 text-lg font-semibold text-white bg-gradient-to-r from-indigo-500 to-indigo-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-indigo-400"
>
白嫖 CF 的 Flux 生成图片
</Link>
</li>
<li>
<Link
to="/idioms/game"
className="block w-full text-center px-6 py-4 text-lg font-semibold text-white bg-gradient-to-r from-green-500 to-green-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-green-400"
>
看图猜成语游戏
</Link>
</li>
<li>
<Link
to="https://github.com/aigem/cf-flux-remix"
className="block w-full text-center px-6 py-3 text-lg font-semibold text-white bg-gradient-to-r from-indigo-500 to-indigo-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-indigo-400"
className="block w-full text-center px-6 py-4 text-lg font-semibold text-white bg-gradient-to-r from-yellow-500 to-yellow-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-yellow-400"
>
访问 Github
</Link>
</li>
<li>
<Link
to="https://github.com/aigem/CFr2-webdav"
className="block w-full text-center px-6 py-3 text-lg font-semibold text-white bg-gradient-to-r from-indigo-500 to-indigo-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-indigo-400"
className="block w-full text-center px-6 py-4 text-lg font-semibold text-white bg-gradient-to-r from-blue-500 to-blue-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-400"
>
Workers+R2搭建个人免费webdav网盘
</Link>
</li>
<li>
<Link
to="https://github.com/aigem/CFr2-webdav"
className="block w-full text-center px-6 py-3 text-lg font-semibold text-white bg-gradient-to-r from-indigo-500 to-indigo-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-indigo-400"
className="block w-full text-center px-6 py-4 text-lg font-semibold text-white bg-gradient-to-r from-red-500 to-red-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-red-400"
>
自行搭建:全平台视频下载助手
</Link>
</li>
{/* 可以在这里添加更多的导航项 */}
</ul>
</nav>
<div className="mt-8 text-white text-center">
<h2 className="text-2xl font-bold mb-4">系统状态</h2>
<p>CF AI 状态: <span className={cfAiStatus === "已连接" ? "text-green-400" : "text-red-400"}>{cfAiStatus}</span></p>
<p>API Key: <span className={configStatus.API_KEY === "已设置" ? "text-green-400" : "text-red-400"}>{configStatus.API_KEY}</span></p>
<p>翻译模型: {configStatus.CF_TRANSLATE_MODEL}</p>
<p>CF 账户列表: <span className={configStatus.CF_ACCOUNT_LIST === "已设置" ? "text-green-400" : "text-red-400"}>{configStatus.CF_ACCOUNT_LIST}</span></p>
<p>自定义模型映射: <span className={configStatus.CUSTOMER_MODEL_MAP === "已设置" ? "text-green-400" : "text-red-400"}>{configStatus.CUSTOMER_MODEL_MAP}</span></p>
</div>
</div>
</div>
);
Expand Down
16 changes: 16 additions & 0 deletions app/routes/idioms/api.receive-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { json } from "@remix-run/cloudflare";
import type { ActionFunction } from "@remix-run/cloudflare";

export const action: ActionFunction = async ({ request }: { request: Request }) => {
const data = await request.json();

// 验证数据格式
if (!data["成语"] || !data["成语解释"] || !data["混淆成语1"] || !data["混淆成语2"] ||
!data["图1"] || !data["图2"] || !data["图3"] || !data["图4"]) {
return json({ error: "数据格式不正确。" }, { status: 400 });
}

// 这里你可以处理数据,例如存储到数据库
// 为了简单起见,我们直接返回接收到的数据
return json({ message: "数据接收成功", data });
};
200 changes: 200 additions & 0 deletions app/routes/idioms/game.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import { useLoaderData, useActionData, Form, useSubmit } from "@remix-run/react";
import { json } from "@remix-run/cloudflare";
import type { LoaderFunction, ActionFunction } from "@remix-run/cloudflare";
import { useState, useEffect } from "react";
import { createAppContext } from "../../context";
import type { AppLoadContext } from "@remix-run/cloudflare";

type GameData = {
"成语": string;
"成语解释": string;
"混淆成语1": string;
"混淆成语2": string;
"图1": string;
"图2": string;
"图3": string;
"图4": string;
};

export const loader: LoaderFunction = async ({ request, context }: { request: Request; context: AppLoadContext }) => {
const url = new URL(request.url);
const isNewGame = url.searchParams.get("new") === "true";

if (isNewGame) {
const appContext = createAppContext(context);
const { config } = appContext;
const webhookUrl = config.CHENGYU_WEBHOOK_URL || "https://aigenai-aiflow.hf.space/webhook/chengyu";

try {
const response = await fetch(webhookUrl);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const gameData: GameData = await response.json();
return json(gameData);
} catch (error) {
console.error("获取成语数据失败:", error);
return json({ error: "获取成语数据失败,请稍后再试。" }, { status: 500 });
}
}

return json({});
};

export const action: ActionFunction = async ({ request }: { request: Request }) => {
const formData = await request.formData();
const selectedIdiom = formData.get("selectedIdiom");
const correctIdiom = formData.get("correctIdiom");

if (selectedIdiom === correctIdiom) {
return json({ result: "正确" });
} else {
return json({ result: "错误" });
}
};

export default function Game() {
const loaderData = useLoaderData<GameData | { error?: string }>();
const actionData = useActionData();
const [currentImage, setCurrentImage] = useState(0);
const [gameData, setGameData] = useState<GameData | null>(null);
const [gameStarted, setGameStarted] = useState(false);
const [showContinueButton, setShowContinueButton] = useState(false);
const [score, setScore] = useState(0);
const [round, setRound] = useState(0);
const submit = useSubmit();

const images = gameData ? [gameData["图1"], gameData["图2"], gameData["图3"], gameData["图4"]] : [];

useEffect(() => {
if ('成语' in loaderData) {
setGameData(loaderData as GameData);
setGameStarted(true);
setRound((prev) => prev + 1);
}
}, [loaderData]);

useEffect(() => {
if (gameStarted && images.length > 0) {
const interval = setInterval(() => {
setCurrentImage((prev) => (prev + 1) % images.length);
}, 2000); // 增加到2秒,让用户有更多时间观察图片
return () => clearInterval(interval);
}
}, [gameStarted, images.length]);

useEffect(() => {
if (actionData?.result) {
setShowContinueButton(true);
if (actionData.result === "正确") {
setScore((prev) => prev + 1);
}
}
}, [actionData]);

const startNewGame = () => {
submit({ new: "true" }, { method: "get" });
setShowContinueButton(false);
};

if ('error' in loaderData) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-purple-600 via-pink-500 to-red-500">
<div className="bg-white bg-opacity-10 backdrop-filter backdrop-blur-lg rounded-3xl shadow-2xl p-10 max-w-md w-full">
<h1 className="text-4xl font-extrabold text-white mb-8 text-center">出错了</h1>
<p className="text-center text-white">{loaderData.error}</p>
<button
onClick={startNewGame}
className="mt-8 w-full px-6 py-3 text-lg font-semibold text-white bg-gradient-to-r from-indigo-500 to-indigo-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-indigo-400"
>
重试
</button>
</div>
</div>
);
}

if (!gameStarted) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-purple-600 via-pink-500 to-red-500">
<div className="bg-white bg-opacity-10 backdrop-filter backdrop-blur-lg rounded-3xl shadow-2xl p-10 max-w-md w-full">
<h1 className="text-4xl font-extrabold text-white mb-8 text-center">看图猜成语</h1>
<p className="text-white text-center mb-8">准备好挑战你的成语知识了吗?</p>
<button
onClick={startNewGame}
className="w-full px-6 py-3 text-lg font-semibold text-white bg-gradient-to-r from-indigo-500 to-indigo-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-indigo-400"
>
开始游戏
</button>
</div>
</div>
);
}

return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-purple-600 via-pink-500 to-red-500">
<div className="bg-white bg-opacity-10 backdrop-filter backdrop-blur-lg rounded-3xl shadow-2xl p-10 max-w-md w-full">
<h1 className="text-4xl font-extrabold text-white mb-8 text-center">看图猜成语</h1>
<div className="text-white text-center mb-4">
<p className="text-xl">得分: <span className="font-bold">{score}</span></p>
<p className="text-xl">回合: <span className="font-bold">{round}</span></p>
</div>
{gameData && (
<>
<div className="mb-8 relative">
<img
src={`data:image/jpeg;base64,${images[currentImage]}`}
alt={`成语图${currentImage + 1}`}
className="w-full h-64 object-cover rounded-xl shadow-lg"
/>
<div className="absolute bottom-2 right-2 bg-black bg-opacity-50 text-white px-2 py-1 rounded">
{currentImage + 1} / 4
</div>
</div>
<Form method="post" className="space-y-4">
<input type="hidden" name="correctIdiom" value={gameData["成语"]} />
<div className="grid grid-cols-1 gap-4">
{[gameData["成语"], gameData["混淆成语1"], gameData["混淆成语2"]].sort(() => Math.random() - 0.5).map((idiom, index) => (
<button
key={index}
type="submit"
name="selectedIdiom"
value={idiom}
className="w-full px-6 py-3 text-lg font-semibold text-white bg-gradient-to-r from-indigo-500 to-indigo-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-indigo-400 disabled:opacity-50"
disabled={showContinueButton}
>
{idiom}
</button>
))}
</div>
</Form>
</>
)}
{actionData?.result && (
<div className={`mt-6 text-center text-2xl font-bold ${actionData.result === "正确" ? "text-green-400" : "text-red-400"}`}>
{actionData.result === "正确" ? "恭喜你,答对了!" : "很遗憾,答错了!"}
</div>
)}
{actionData?.result === "错误" && (
<div className="mt-2 text-center text-white">
正确答案: <span className="font-bold">{gameData?.["成语"]}</span>
</div>
)}
{gameData && (
<div className="mt-6 text-center text-white">
<h2 className="text-xl font-bold mb-2">成语解释:</h2>
<p className="text-lg">{gameData["成语解释"]}</p>
</div>
)}
{showContinueButton && (
<button
onClick={startNewGame}
className="mt-6 w-full px-6 py-3 text-lg font-semibold text-white bg-gradient-to-r from-green-500 to-green-700 rounded-xl transition transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-green-400"
>
继续游戏
</button>
)}
</div>
</div>
);
}
14 changes: 14 additions & 0 deletions remix.env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// <reference types="@remix-run/cloudflare" />
/// <reference types="vite/client" />

import type { AppLoadContext } from "@remix-run/cloudflare";

declare module "@remix-run/cloudflare" {
interface AppLoadContext {
cloudflare: {
env: {
[key: string]: string;
};
};
}
}
8 changes: 3 additions & 5 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"types": [
"@remix-run/cloudflare",
"vite/client",
"@cloudflare/workers-types/2023-07-01"
"@remix-run/cloudflare",
"vite/client",
"@cloudflare/workers-types"
],
"isolatedModules": true,
"esModuleInterop": true,
Expand All @@ -29,8 +29,6 @@
"paths": {
"~/*": ["./app/*"]
},

// Vite takes care of building everything, not tsc.
"noEmit": true
}
}
8 changes: 2 additions & 6 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { vitePlugin as remix } from "@remix-run/dev";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
import { vitePlugin as remix } from "@remix-run/dev";

export default defineConfig({
plugins: [remix(), tsconfigPaths()],
define: {
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
},
plugins: [remix()],
});

0 comments on commit 9f4b26d

Please sign in to comment.