first commit

This commit is contained in:
dekun
2026-06-10 19:59:27 +08:00
commit d141623070
813 changed files with 61301 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+109
View File
@@ -0,0 +1,109 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 60 9% 98%;
--foreground: 0 0% 32%;
--card: 60 9% 98%;
--card-foreground: 0 0% 32%;
--popover: 60 9% 98%;
--popover-foreground: 0 0% 32%;
--primary: 0 0% 32%;
--primary-foreground: 60 9.1% 97.8%;
--secondary: 60 5% 96%;
--secondary-foreground: 0 0% 32%;
--muted: 60 4.8% 95.9%;
--muted-foreground: 25 5.3% 44.7%;
--accent: 20 5.9% 94%;
--accent-foreground: 24 9.8% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 60 9.1% 97.8%;
--border: 20 5.9% 90%;
--input: 24 6% 85%;
--ring: 0 0% 32%;
--radius: 0.5rem;
}
.dark {
--background: 24 10% 10%;
--foreground: 60 9.1% 97.8%;
--card: 24 10% 10%;
--card-foreground: 60 9.1% 97.8%;
--popover: 24 10% 10%;
--popover-foreground: 60 9.1% 97.8%;
--primary: 60 9.1% 97.8%;
--primary-foreground: 0 0% 32%;
--secondary: 0 0% 20%;
--secondary-foreground: 60 9.1% 97.8%;
--muted: 24 10% 10%;
--muted-foreground: 24 5.4% 66%;
--accent: 0 0% 20%;
--accent-foreground: 60 9.1% 97.8%;
--destructive: 0 74% 42%;
--destructive-foreground: 60 9.1% 97.8%;
--border: 30 6% 25%;
--input: 33 5% 32%;
--ring: 20 6% 90%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply gap flex flex-col bg-background text-foreground;
}
body {
font-family: 'LXGW WenKai Screen';
font-weight: normal;
}
body,
html {
@apply h-full;
}
footer {
padding-bottom: max(env(safe-area-inset-bottom), 8px);
}
}
@layer utilities {
.gap {
@apply gap-4 sm:gap-6;
}
}
@layer utilities {
::-webkit-scrollbar {
--bar-width: 5px;
width: var(--bar-width);
height: var(--bar-width);
}
::-webkit-scrollbar-thumb {
@apply rounded-md bg-border;
}
}
+53
View File
@@ -0,0 +1,53 @@
import "./globals.css";
import type { Metadata, Viewport } from "next";
import React from "react";
import Umami from "@/components/umami";
import { ThemeProvider } from "next-themes";
export const metadata: Metadata = {
title: "AI 算卦 - 在线卜卦 GPT4 解读",
description:
"AI 算卦 - 通过进行六次硬币的随机卜筮,生成卦象,并使用 AI 对卦象进行分析|AI 算命、在线算命、在线算卦、周易易经64卦",
appleWebApp: {
title: "AI 算卦",
},
};
export const viewport: Viewport = {
viewportFit: "cover",
width: "device-width",
initialScale: 1,
maximumScale: 1,
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "#f5f5f4" },
{ media: "(prefers-color-scheme: dark)", color: "#333333" },
],
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="cn" suppressHydrationWarning>
<head>
<link
rel="stylesheet"
href="https://registry.npmmirror.com/lxgw-wenkai-screen-web/latest/files/lxgwwenkaiscreen/result.css"
/>
</head>
<body>
<ThemeProvider
enableSystem
attribute="class"
defaultTheme="system"
disableTransitionOnChange
>
{children}
</ThemeProvider>
<Umami />
</body>
</html>
);
}
+13
View File
@@ -0,0 +1,13 @@
import Header from "@/components/header";
import Divination from "@/components/divination";
import Footer from "@/components/footer";
export default function Home() {
return (
<>
<Header />
<Divination />
<Footer />
</>
);
}
+100
View File
@@ -0,0 +1,100 @@
"use server";
import { streamText } from "ai";
import { createOpenAI } from "@ai-sdk/openai";
import { createStreamableValue } from "ai/rsc";
import { ERROR_PREFIX } from "@/lib/constant";
import {
extractChangeDetails,
extractZhangMingRen,
readGuaMarkdown,
} from "@/lib/content/zhouyi";
const model =
process.env.OPENAI_MODEL ?? "huihui_ai/gemma-4-abliterated:e4b";
const openai = createOpenAI({
baseURL: process.env.OPENAI_BASE_URL ?? "https://op.bz121.com/v1",
});
const STREAM_INTERVAL = 60;
const MAX_SIZE = 6;
export async function getAnswer(
prompt: string,
guaMark: string,
guaTitle: string,
guaResult: string,
guaChange: string,
) {
console.log(prompt, guaTitle, guaResult, guaChange);
const stream = createStreamableValue();
try {
const guaDetail = await readGuaMarkdown(guaMark);
const explain = extractZhangMingRen(guaDetail) ?? "";
const changeList = extractChangeDetails(guaDetail, guaChange, guaTitle);
const { fullStream } = streamText({
temperature: 0.5,
model: openai(model),
messages: [
{
role: "system",
content: `你是一位精通《周易》的AI助手,根据用户提供的卦象和问题,提供准确的卦象解读和实用建议
任务要求:逻辑清晰,语气得当
1. 解读卦象:分析主卦、变爻及变卦,解读整体趋势和吉凶
2. 关联问题:针对用户问题,结合卦象信息,提供具体分析
3. 提供建议:根据卦象启示,给出切实可行的建议,帮助用户解决实际问题`,
},
{
role: "user",
content: `我摇到的卦象:${guaTitle} ${guaResult} ${guaChange}
我的问题:${prompt}
${explain}
${changeList.join("\n")}`,
},
],
maxRetries: 0,
});
let buffer = "";
let done = false;
const intervalId = setInterval(() => {
if (done && buffer.length === 0) {
clearInterval(intervalId);
stream.done();
return;
}
if (buffer.length <= MAX_SIZE) {
stream.update(buffer);
buffer = "";
} else {
const chunk = buffer.slice(0, MAX_SIZE);
buffer = buffer.slice(MAX_SIZE);
stream.update(chunk);
}
}, STREAM_INTERVAL);
(async () => {
for await (const part of fullStream) {
switch (part.type) {
case "text-delta":
buffer += part.textDelta;
break;
case "error":
const err = part.error as any;
stream.update(ERROR_PREFIX + (err.message ?? err.toString()));
break;
}
}
})()
.catch(console.error)
.finally(() => {
done = true;
});
return { data: stream.value };
} catch (err: any) {
stream.done();
return { error: err.message ?? err };
}
}