Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
guaguaguaxia committed Feb 9, 2023
0 parents commit d8b9ebf
Show file tree
Hide file tree
Showing 32 changed files with 3,843 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
OPENAI_API_KEY=
NEXT_PUBLIC_USE_USER_KEY=false
# OPENAI_MODEL=text-chat-davinci-002-20221122
OPENAI_MODEL=text-davinci-003
40 changes: 40 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
.env

# idea
.idea
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# [Chat Simplifier](https://chat-simplifier.vercel.app/)
[![](https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true)](https://chat.imzbb.cc)

This project simplify chat content for you using AI.

[![Chat Simplifier](./public/screenshot.png)](https://chat-simplifier.vercel.app/)

## How it works

This project uses the [OpenAI GPT-3 API](https://openai.com/api/) (specifically, text-davinci-003) and [Vercel Edge functions](https://vercel.com/features/edge-functions) with streaming. It constructs a prompt based on the form and user input, sends it to the GPT-3 API via a Vercel Edge function, then streams the response back to the application.

## Running Locally

After cloning the repo, go to [OpenAI](https://beta.openai.com/account/api-keys) to make an account and put your API key in a file called `.env`.

Then, run the application in the command line and it will be available at `http://localhost:3000`.

```bash
npm run dev
```

## One-Click Deploy

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=vercel-examples):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fzhengbangbo%2Fchat-simplifier&env=OPENAI_API_KEY,NEXT_PUBLIC_USE_USER_KEY,OPENAI_MODEL&envDescription=%E7%82%B9%E5%87%BB%E5%8F%B3%E4%BE%A7%E3%80%8CLearn%20More%E3%80%8D%E6%9F%A5%E7%9C%8B%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E8%AF%B4%E6%98%8E&envLink=https%3A%2F%2Fgithub.com%2Fzhengbangbo%2Fchat-simplifier%2Fwiki%2FDeploy&project-name=chat-simplifier&repository-name=chat-simplifier)

## Credits

Inspired by [TwtterBio](https://github.com/Nutlope/twitterbio) and [Jimmy Lv](https://www.bilibili.com/video/BV17M411i7B6).

## 支持

如果你觉得这个工具对您有帮助,可以帮作者买一杯果汁 🍹 表示支持

![](https://imzbb.cc/img/sponsorship.png)
79 changes: 79 additions & 0 deletions components/DropDown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Menu, Transition } from "@headlessui/react";
import {
CheckIcon,
ChevronDownIcon,
ChevronUpIcon,
} from "@heroicons/react/20/solid";
import { Fragment } from "react";
import { useTranslations } from 'next-intl'

function classNames(...classes: string[]) {
return classes.filter(Boolean).join(" ");
}

export type FormType = "paragraphForm" | "outlineForm";

interface DropDownProps {
form: FormType;
setForm: (form: FormType) => void;
}

let forms: FormType[] = ["paragraphForm", "outlineForm"]

export default function DropDown({ form, setForm}: DropDownProps) {
const t = useTranslations('Index')
return (
<Menu as="div" className="relative block text-left w-full">
<div>
<Menu.Button className="inline-flex w-full justify-between items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-black">
{t(form)}
<ChevronUpIcon
className="-mr-1 ml-2 h-5 w-5 ui-open:hidden"
aria-hidden="true"
/>
<ChevronDownIcon
className="-mr-1 ml-2 h-5 w-5 hidden ui-open:block"
aria-hidden="true"
/>
</Menu.Button>
</div>

<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
className="absolute left-0 z-10 mt-2 w-full origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
key={form}
>
<div className="">
{forms.map((formItem) => (
<Menu.Item key={formItem}>
{({ active }) => (
<button
onClick={() => setForm(formItem)}
className={classNames(
active ? "bg-gray-100 text-gray-900" : "text-gray-700",
form === formItem ? "bg-gray-200" : "",
"px-4 py-2 text-sm w-full text-left flex items-center space-x-2 justify-between"
)}
>
<span>{t(formItem)}</span>
{form === formItem ? (
<CheckIcon className="w-4 h-4 text-bold" />
) : null}
</button>
)}
</Menu.Item>
))}
</div>
</Menu.Items>
</Transition>
</Menu>
);
}
54 changes: 54 additions & 0 deletions components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Link from "next/link";

export default function Footer() {
return (
<footer className="text-center h-16 sm:h-20 w-full sm:pt-2 pt-4 border-t mt-5 flex sm:flex-row flex-col justify-between items-center px-3 space-y-3 sm:mb-0 mb-3">
<div>
Powered by{" "}
<a
href="https://openai.com/"
target="_blank"
rel="noreferrer"
className="font-bold hover:underline transition underline-offset-2"
>
OpenAI{" "}
</a>
and{" "}
<a
href="https://vercel.com/"
target="_blank"
rel="noreferrer"
className="font-bold hover:underline transition underline-offset-2"
>
Vercel Edge Functions.
</a>
</div>
<div className="flex space-x-4 pb-4 sm:pb-0">
<Link
href="https://twitter.com/zhengbangbo"
className="group"
aria-label="TaxPal on Twitter"
>
<svg
aria-hidden="true"
className="h-6 w-6 fill-slate-500 group-hover:fill-slate-700"
>
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0 0 22 5.92a8.19 8.19 0 0 1-2.357.646 4.118 4.118 0 0 0 1.804-2.27 8.224 8.224 0 0 1-2.605.996 4.107 4.107 0 0 0-6.993 3.743 11.65 11.65 0 0 1-8.457-4.287 4.106 4.106 0 0 0 1.27 5.477A4.073 4.073 0 0 1 2.8 9.713v.052a4.105 4.105 0 0 0 3.292 4.022 4.093 4.093 0 0 1-1.853.07 4.108 4.108 0 0 0 3.834 2.85A8.233 8.233 0 0 1 2 18.407a11.615 11.615 0 0 0 6.29 1.84" />
</svg>
</Link>
<Link
href="https://github.com/zhengbangbo/chat-simplifier"
className="group"
aria-label="TaxPal on GitHub"
>
<svg
aria-hidden="true"
className="h-6 w-6 fill-slate-500 group-hover:fill-slate-700"
>
<path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2Z" />
</svg>
</Link>
</div>
</footer>
);
}
14 changes: 14 additions & 0 deletions components/GitHub.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default function Github({ className }: { className?: string }) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
fill="currentColor"
viewBox="0 0 24 24"
className={className}
>
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
</svg>
);
}
51 changes: 51 additions & 0 deletions components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Image from "next/image";
import Link from "next/link";
import { useRouter } from 'next/router'
import { useTranslations } from "next-intl";
import Github from "./GitHub";

export default function Header() {
const t = useTranslations('Index')
const { locale, locales, route } = useRouter()
const otherLocale = locales?.find((cur) => cur !== locale)

return (
<header className="flex justify-between items-center w-full mt-5 border-b-2 pb-7 sm:px-4 px-2">
<Link href="/" className="flex space-x-3">
<Image
alt="header text"
src="/icon.svg"
className="sm:w-12 sm:h-12 w-8 h-8"
width={32}
height={32}
/>
<h1 className="sm:text-4xl text-2xl font-bold ml-2 tracking-tight">
{t('title')}
</h1>
</Link>
<div className="flex gap-2">
{
otherLocale && (
<div
className="relative font-medium text-black-600 before:absolute before:-bottom-1 before:h-0.5 before:w-full before:scale-x-0 before:bg-indigo-600 before:transition hover:before:scale-x-100">
<Link href={route} locale={otherLocale}>
{t('switchLocale', { locale: otherLocale })}
</Link>
</div>
)
}
{" / "}
<a
className="relative font-medium text-black-600 before:absolute before:-bottom-1 before:h-0.5 before:w-full before:scale-x-0 before:bg-indigo-600 before:transition hover:before:scale-x-100"
href="https://github.com/zhengbangbo/chat-simplifier/blob/main/README.md#one-click-deploy"
target="_blank"
rel="noopener noreferrer"
>
<p>{t('deployWiki')}</p>
</a>
</div>


</header>
);
}
23 changes: 23 additions & 0 deletions components/LoadingDots.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import styles from "../styles/loading-dots.module.css";

const LoadingDots = ({
color = "#000",
style = "small",
}: {
color: string;
style: string;
}) => {
return (
<span className={style == "small" ? styles.loading2 : styles.loading}>
<span style={{ backgroundColor: color }} />
<span style={{ backgroundColor: color }} />
<span style={{ backgroundColor: color }} />
</span>
);
};

export default LoadingDots;

LoadingDots.defaultProps = {
style: "small",
};
23 changes: 23 additions & 0 deletions components/ResizablePanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { motion } from "framer-motion";
import useMeasure from "react-use-measure";

export default function ResizablePanel({
children,
}: {
children: React.ReactNode;
}) {
let [ref, { height }] = useMeasure();

return (
<motion.div
animate={height ? { height } : {}}
style={height ? { height } : {}}
className="relative w-full overflow-hidden"
transition={{ type: "tween", duration: 0.5 }}
>
<div ref={ref} className={height ? "absolute inset-x-0" : "relative"}>
{children}
</div>
</motion.div>
);
}
25 changes: 25 additions & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"Index": {
"title": "Chat Simplifier",
"switchLocale": "{locale, select,zh {中文} en {English} other {}}",
"deployWiki": "Deploy your own website?",
"description": "Simplify your chat content in seconds",
"slogan": "Too many group messages? It's too long to look!",
"step0": "Paste your OpenAI API Key",
"openaiApiKeyPlaceholder": "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"step1": "Paste your chat content",
"helpPageLink": "(Click here to view tutorials)",
"placeholder": "Choose more chat content and copy it. It usually contains nicknames, times, and content.",
"step2": "Select the form of the output.",
"simplifierButton": "Simplify the chat content",
"privacyPolicy1": "It is not recommended to upload chat that is too private. For more information, please see",
"privacyPolicy2": "Privacy Statement",
"simplifiedContent": "Simplified content",
"paragraphForm": "Paragraph",
"paragraphFormPrompt": "Please summarize the chat content between <|start|> and <|end|>. It is required to be concise and to the point and output in the form of a paragraph.\n\n<|start|>",
"outlineForm": "Outline",
"outlineFormPrompt": "Please summarize the chat content between <|start|> and <|end|>. It is required to be concise and output in the form of an outline containing a list.\n\n<|start|>",
"pasteButton": "Paste",
"clearButton": "Clear"
}
}
25 changes: 25 additions & 0 deletions messages/zh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"Index": {
"title": "聊天内容简化器",
"switchLocale": "{locale, select,zh {中文} en {English} other {}}",
"deployWiki": "部署自己的网站?",
"description": "简化您的聊天内容",
"slogan": "群消息太多?太长不看!",
"step0": "粘贴你的 OpenAI API Key",
"openaiApiKeyPlaceholder": "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"step1": "粘贴你的聊天内容",
"helpPageLink": "(点击这里查看教程)",
"placeholder": "多选聊天内容,复制。通常包含昵称、时间和内容。",
"step2": "选择输出结果的形式。",
"simplifierButton": "简化聊天内容",
"simplifiedContent": "简化后的内容",
"privacyPolicy1": "不建议上传过于隐私的聊天内容,详情查看",
"privacyPolicy2": "《隐私声明》",
"paragraphForm": "段落",
"paragraphFormPrompt": "请总结<|start|>与<|end|>之间的聊天内容。要求简明扼要,以一段话的形式输出。\n\n<|start|>",
"outlineForm": "大纲",
"outlineFormPrompt": "请总结<|start|>与<|end|>之间的聊天内容。要求简明扼要,以包含列表的大纲形式输出。\n\n<|start|>",
"pasteButton": "粘贴",
"clearButton": "清空"
}
}
8 changes: 8 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
i18n: {
locales: ['en', 'zh'],
defaultLocale: 'en',
},
}
Loading

1 comment on commit d8b9ebf

@vercel
Copy link

@vercel vercel bot commented on d8b9ebf Feb 9, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.