div]:w-full", className)} {...props} />;
13 | }
14 |
15 | export default function Home() {
16 | const { toast } = useToast();
17 | const [endpoints, setEndpoints] = useState([]);
18 |
19 | useEffect(() => {
20 | fetch("/api/endpoint/list", { method: "POST" })
21 | .then((response) => response.json())
22 | .then((data) => setEndpoints(data.data));
23 | }, []);
24 |
25 | const copyToClipboard = (id: string, prompt: string) => {
26 | const body = { prompt: prompt };
27 | const currentHost = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : "");
28 | const curl = `curl -X 'POST' '${currentHost}/api/endpoint/${id}' \\\n -H 'Content-Type: application/json' \\\n -d '${JSON.stringify(body)}' `;
29 | navigator.clipboard.writeText(curl);
30 | toast({
31 | title: "Copied to clipboard",
32 | description: "The cURL command has been copied to your clipboard.",
33 | });
34 | };
35 |
36 | return (
37 |
38 |
39 | {endpoints &&
40 | endpoints.map((endpoint: any, index: number) => (
41 |
42 |
43 |
44 | {endpoint.typeName}
45 |
46 |
47 |
48 |
64 |
65 |
66 |
67 |
70 |
73 |
74 |
75 |
76 | ))}
77 |
78 |
79 | );
80 | }
81 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cooder-org/json-translator/db4132782f79b12fcca068985df3fa67d2bd86b3/app/favicon.ico
--------------------------------------------------------------------------------
/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 0 0% 100%;
8 | --foreground: 222.2 84% 4.9%;
9 |
10 | --muted: 210 40% 96.1%;
11 | --muted-foreground: 215.4 16.3% 46.9%;
12 |
13 | --popover: 0 0% 100%;
14 | --popover-foreground: 222.2 84% 4.9%;
15 |
16 | --card: 0 0% 100%;
17 | --card-foreground: 222.2 84% 4.9%;
18 |
19 | --border: 214.3 31.8% 91.4%;
20 | --input: 214.3 31.8% 91.4%;
21 |
22 | --primary: 222.2 47.4% 11.2%;
23 | --primary-foreground: 210 40% 98%;
24 |
25 | --secondary: 210 40% 96.1%;
26 | --secondary-foreground: 222.2 47.4% 11.2%;
27 |
28 | --accent: 210 40% 96.1%;
29 | --accent-foreground: 222.2 47.4% 11.2%;
30 |
31 | --destructive: 0 84.2% 60.2%;
32 | --destructive-foreground: 210 40% 98%;
33 |
34 | --ring: 215 20.2% 65.1%;
35 |
36 | --radius: 0.5rem;
37 | }
38 |
39 | .dark {
40 | --background: 222.2 84% 4.9%;
41 | --foreground: 210 40% 98%;
42 |
43 | --muted: 217.2 32.6% 17.5%;
44 | --muted-foreground: 215 20.2% 65.1%;
45 |
46 | --popover: 222.2 84% 4.9%;
47 | --popover-foreground: 210 40% 98%;
48 |
49 | --card: 222.2 84% 4.9%;
50 | --card-foreground: 210 40% 98%;
51 |
52 | --border: 217.2 32.6% 17.5%;
53 | --input: 217.2 32.6% 17.5%;
54 |
55 | --primary: 210 40% 98%;
56 | --primary-foreground: 222.2 47.4% 11.2%;
57 |
58 | --secondary: 217.2 32.6% 17.5%;
59 | --secondary-foreground: 210 40% 98%;
60 |
61 | --accent: 217.2 32.6% 17.5%;
62 | --accent-foreground: 210 40% 98%;
63 |
64 | --destructive: 0 62.8% 30.6%;
65 | --destructive-foreground: 0 85.7% 97.3%;
66 |
67 | --ring: 217.2 32.6% 17.5%;
68 | }
69 | }
70 |
71 | @layer base {
72 | * {
73 | @apply border-border;
74 | }
75 | body {
76 | @apply bg-background text-foreground;
77 | }
78 | }
--------------------------------------------------------------------------------
/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import "./globals.css";
2 | import type { Metadata } from "next";
3 | import { Inter } from "next/font/google";
4 | import { MainNav } from "@/components/main-nav";
5 | import { Toaster } from "@/components/ui/toaster"
6 |
7 | const inter = Inter({ subsets: ["latin"] });
8 |
9 | export const metadata: Metadata = {
10 | title: "Json Translator",
11 | description: "Generated by cooder.org",
12 | };
13 |
14 | export default function RootLayout({ children }: { children: React.ReactNode }) {
15 | return (
16 |
17 |
18 |
25 | {children}
26 |
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/app/page.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@/components/ui/button";
2 | import Link from "next/link";
3 |
4 | export default function Home() {
5 | return (
6 | <>
7 |
8 |
9 |
Make LLM As Your API Server
10 | Types are all you need
11 |
12 |
13 |
16 |
19 |
20 |
21 | >
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/app/playground/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { use, useEffect, useState } from "react";
4 | import CodeEditor from "@uiw/react-textarea-code-editor";
5 | import { Triangle } from "react-loader-spinner";
6 | import { Button } from "@/components/ui/button";
7 | import { useToast } from "@/components/ui/use-toast";
8 |
9 | export default function Home() {
10 | const { toast } = useToast();
11 | const [loading, setLoading] = useState(false);
12 | const [formData, setFormData] = useState({
13 | typeName: "ShareOrNot",
14 | schema:
15 | "// The following is a schema definition for determining whether a user wants to share a post or not:\n\nexport interface ShareOrNot {\n isShare: boolean;\n url: string;\n comment: string;\n}",
16 | output: "",
17 | prompt: "https://github.com/shengxia/RWKV_Role_Playing_API A Flask-based RWKV role-playing API",
18 | });
19 |
20 | useEffect(() => {
21 | const params = new URLSearchParams(window.location.search);
22 | const id = params.get("id");
23 | if (id) {
24 | const fetchData = async () => {
25 | setLoading(true);
26 | const response = await fetch(`/api/endpoint/${id}`);
27 | const rsp = await response.json();
28 | setFormData(rsp.data);
29 | setLoading(false);
30 | };
31 | fetchData();
32 | }
33 | }, []);
34 |
35 | const handleChange = (event: React.ChangeEvent
) => {
36 | const { name, value } = event.target;
37 | setFormData((prevState) => ({ ...prevState, [name]: value }));
38 | };
39 |
40 | const onClick = async () => {
41 | setLoading(true);
42 | const response = await fetch("/api/translate", {
43 | method: "POST",
44 | headers: {
45 | "Content-Type": "application/json",
46 | },
47 | body: JSON.stringify(formData),
48 | });
49 | const data = await response.json();
50 | setFormData((prevState) => ({ ...prevState, output: JSON.stringify(data, null, 2) }));
51 | setLoading(false);
52 | };
53 |
54 | const onAddEndpoint = async () => {
55 | setLoading(true);
56 | const response = await fetch("/api/endpoint/add", {
57 | method: "POST",
58 | headers: {
59 | "Content-Type": "application/json",
60 | },
61 | body: JSON.stringify(formData),
62 | });
63 | const data = await response.json();
64 | if (data.success) {
65 | toast({
66 | title: "Success",
67 | description: `Add endpoint success. id: ${data.endpointId}`,
68 | });
69 | } else {
70 | toast({
71 | variant: "destructive",
72 | title: "Error",
73 | description: `Add endpoint error: ${data?.error?.code}`,
74 | });
75 | }
76 | setLoading(false);
77 | };
78 |
79 | return (
80 | <>
81 | {loading && (
82 |
89 | )}
90 |
91 |
92 |
93 |
94 |
95 |
98 |
99 |
107 |
108 |
109 |
110 |
111 |
112 |
115 |
116 |
117 |
123 | setFormData({
124 | ...formData,
125 | schema: e.target.value,
126 | })
127 | }
128 | padding={15}
129 | style={{
130 | minHeight: 300,
131 | fontSize: 12,
132 | fontFamily: "ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
133 | }}
134 | />
135 |
136 |
137 |
138 |
139 |
140 |
143 |
144 |
145 |
152 |
153 |
154 |
155 |
156 |
163 |
164 |
165 |
166 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
182 |
183 |
196 |
197 |
198 |
199 |
200 | >
201 | );
202 | }
203 |
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "default",
4 | "rsc": true,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.js",
8 | "css": "app/globals.css",
9 | "baseColor": "slate",
10 | "cssVariables": true
11 | },
12 | "aliases": {
13 | "components": "@/components",
14 | "utils": "@/lib/utils"
15 | }
16 | }
--------------------------------------------------------------------------------
/components/main-nav.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | export function MainNav({
6 | className,
7 | ...props
8 | }: React.HTMLAttributes) {
9 | return (
10 |
39 | )
40 | }
--------------------------------------------------------------------------------
/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Slot } from "@radix-ui/react-slot"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
9 | {
10 | variants: {
11 | variant: {
12 | default: "bg-primary text-primary-foreground hover:bg-primary/90",
13 | destructive:
14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90",
15 | outline:
16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
17 | secondary:
18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19 | ghost: "hover:bg-accent hover:text-accent-foreground",
20 | link: "text-primary underline-offset-4 hover:underline",
21 | },
22 | size: {
23 | default: "h-10 px-4 py-2",
24 | sm: "h-9 rounded-md px-3",
25 | lg: "h-11 rounded-md px-8",
26 | icon: "h-10 w-10",
27 | },
28 | },
29 | defaultVariants: {
30 | variant: "default",
31 | size: "default",
32 | },
33 | }
34 | )
35 |
36 | export interface ButtonProps
37 | extends React.ButtonHTMLAttributes,
38 | VariantProps {
39 | asChild?: boolean
40 | }
41 |
42 | const Button = React.forwardRef(
43 | ({ className, variant, size, asChild = false, ...props }, ref) => {
44 | const Comp = asChild ? Slot : "button"
45 | return (
46 |
51 | )
52 | }
53 | )
54 | Button.displayName = "Button"
55 |
56 | export { Button, buttonVariants }
57 |
--------------------------------------------------------------------------------
/components/ui/card.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | const Card = React.forwardRef<
6 | HTMLDivElement,
7 | React.HTMLAttributes
8 | >(({ className, ...props }, ref) => (
9 |
17 | ))
18 | Card.displayName = "Card"
19 |
20 | const CardHeader = React.forwardRef<
21 | HTMLDivElement,
22 | React.HTMLAttributes
23 | >(({ className, ...props }, ref) => (
24 |
29 | ))
30 | CardHeader.displayName = "CardHeader"
31 |
32 | const CardTitle = React.forwardRef<
33 | HTMLParagraphElement,
34 | React.HTMLAttributes
35 | >(({ className, ...props }, ref) => (
36 |
44 | ))
45 | CardTitle.displayName = "CardTitle"
46 |
47 | const CardDescription = React.forwardRef<
48 | HTMLParagraphElement,
49 | React.HTMLAttributes
50 | >(({ className, ...props }, ref) => (
51 |
56 | ))
57 | CardDescription.displayName = "CardDescription"
58 |
59 | const CardContent = React.forwardRef<
60 | HTMLDivElement,
61 | React.HTMLAttributes
62 | >(({ className, ...props }, ref) => (
63 |
64 | ))
65 | CardContent.displayName = "CardContent"
66 |
67 | const CardFooter = React.forwardRef<
68 | HTMLDivElement,
69 | React.HTMLAttributes
70 | >(({ className, ...props }, ref) => (
71 |
76 | ))
77 | CardFooter.displayName = "CardFooter"
78 |
79 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
80 |
--------------------------------------------------------------------------------
/components/ui/toast.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import * as ToastPrimitives from "@radix-ui/react-toast"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 | import { X } from "lucide-react"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const ToastProvider = ToastPrimitives.Provider
9 |
10 | const ToastViewport = React.forwardRef<
11 | React.ElementRef,
12 | React.ComponentPropsWithoutRef
13 | >(({ className, ...props }, ref) => (
14 |
22 | ))
23 | ToastViewport.displayName = ToastPrimitives.Viewport.displayName
24 |
25 | const toastVariants = cva(
26 | "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
27 | {
28 | variants: {
29 | variant: {
30 | default: "border bg-background",
31 | destructive:
32 | "destructive group border-destructive bg-destructive text-destructive-foreground",
33 | },
34 | },
35 | defaultVariants: {
36 | variant: "default",
37 | },
38 | }
39 | )
40 |
41 | const Toast = React.forwardRef<
42 | React.ElementRef,
43 | React.ComponentPropsWithoutRef &
44 | VariantProps
45 | >(({ className, variant, ...props }, ref) => {
46 | return (
47 |
52 | )
53 | })
54 | Toast.displayName = ToastPrimitives.Root.displayName
55 |
56 | const ToastAction = React.forwardRef<
57 | React.ElementRef,
58 | React.ComponentPropsWithoutRef
59 | >(({ className, ...props }, ref) => (
60 |
68 | ))
69 | ToastAction.displayName = ToastPrimitives.Action.displayName
70 |
71 | const ToastClose = React.forwardRef<
72 | React.ElementRef,
73 | React.ComponentPropsWithoutRef
74 | >(({ className, ...props }, ref) => (
75 |
84 |
85 |
86 | ))
87 | ToastClose.displayName = ToastPrimitives.Close.displayName
88 |
89 | const ToastTitle = React.forwardRef<
90 | React.ElementRef,
91 | React.ComponentPropsWithoutRef
92 | >(({ className, ...props }, ref) => (
93 |
98 | ))
99 | ToastTitle.displayName = ToastPrimitives.Title.displayName
100 |
101 | const ToastDescription = React.forwardRef<
102 | React.ElementRef,
103 | React.ComponentPropsWithoutRef
104 | >(({ className, ...props }, ref) => (
105 |
110 | ))
111 | ToastDescription.displayName = ToastPrimitives.Description.displayName
112 |
113 | type ToastProps = React.ComponentPropsWithoutRef
114 |
115 | type ToastActionElement = React.ReactElement
116 |
117 | export {
118 | type ToastProps,
119 | type ToastActionElement,
120 | ToastProvider,
121 | ToastViewport,
122 | Toast,
123 | ToastTitle,
124 | ToastDescription,
125 | ToastClose,
126 | ToastAction,
127 | }
128 |
--------------------------------------------------------------------------------
/components/ui/toaster.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import {
4 | Toast,
5 | ToastClose,
6 | ToastDescription,
7 | ToastProvider,
8 | ToastTitle,
9 | ToastViewport,
10 | } from "@/components/ui/toast"
11 | import { useToast } from "@/components/ui/use-toast"
12 |
13 | export function Toaster() {
14 | const { toasts } = useToast()
15 |
16 | return (
17 |
18 | {toasts.map(function ({ id, title, description, action, ...props }) {
19 | return (
20 |
21 |
22 | {title && {title}}
23 | {description && (
24 | {description}
25 | )}
26 |
27 | {action}
28 |
29 |
30 | )
31 | })}
32 |
33 |
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/components/ui/use-toast.ts:
--------------------------------------------------------------------------------
1 | // Inspired by react-hot-toast library
2 | import * as React from "react"
3 |
4 | import type {
5 | ToastActionElement,
6 | ToastProps,
7 | } from "@/components/ui/toast"
8 |
9 | const TOAST_LIMIT = 1
10 | const TOAST_REMOVE_DELAY = 1000000
11 |
12 | type ToasterToast = ToastProps & {
13 | id: string
14 | title?: React.ReactNode
15 | description?: React.ReactNode
16 | action?: ToastActionElement
17 | }
18 |
19 | const actionTypes = {
20 | ADD_TOAST: "ADD_TOAST",
21 | UPDATE_TOAST: "UPDATE_TOAST",
22 | DISMISS_TOAST: "DISMISS_TOAST",
23 | REMOVE_TOAST: "REMOVE_TOAST",
24 | } as const
25 |
26 | let count = 0
27 |
28 | function genId() {
29 | count = (count + 1) % Number.MAX_VALUE
30 | return count.toString()
31 | }
32 |
33 | type ActionType = typeof actionTypes
34 |
35 | type Action =
36 | | {
37 | type: ActionType["ADD_TOAST"]
38 | toast: ToasterToast
39 | }
40 | | {
41 | type: ActionType["UPDATE_TOAST"]
42 | toast: Partial
43 | }
44 | | {
45 | type: ActionType["DISMISS_TOAST"]
46 | toastId?: ToasterToast["id"]
47 | }
48 | | {
49 | type: ActionType["REMOVE_TOAST"]
50 | toastId?: ToasterToast["id"]
51 | }
52 |
53 | interface State {
54 | toasts: ToasterToast[]
55 | }
56 |
57 | const toastTimeouts = new Map>()
58 |
59 | const addToRemoveQueue = (toastId: string) => {
60 | if (toastTimeouts.has(toastId)) {
61 | return
62 | }
63 |
64 | const timeout = setTimeout(() => {
65 | toastTimeouts.delete(toastId)
66 | dispatch({
67 | type: "REMOVE_TOAST",
68 | toastId: toastId,
69 | })
70 | }, TOAST_REMOVE_DELAY)
71 |
72 | toastTimeouts.set(toastId, timeout)
73 | }
74 |
75 | export const reducer = (state: State, action: Action): State => {
76 | switch (action.type) {
77 | case "ADD_TOAST":
78 | return {
79 | ...state,
80 | toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
81 | }
82 |
83 | case "UPDATE_TOAST":
84 | return {
85 | ...state,
86 | toasts: state.toasts.map((t) =>
87 | t.id === action.toast.id ? { ...t, ...action.toast } : t
88 | ),
89 | }
90 |
91 | case "DISMISS_TOAST": {
92 | const { toastId } = action
93 |
94 | // ! Side effects ! - This could be extracted into a dismissToast() action,
95 | // but I'll keep it here for simplicity
96 | if (toastId) {
97 | addToRemoveQueue(toastId)
98 | } else {
99 | state.toasts.forEach((toast) => {
100 | addToRemoveQueue(toast.id)
101 | })
102 | }
103 |
104 | return {
105 | ...state,
106 | toasts: state.toasts.map((t) =>
107 | t.id === toastId || toastId === undefined
108 | ? {
109 | ...t,
110 | open: false,
111 | }
112 | : t
113 | ),
114 | }
115 | }
116 | case "REMOVE_TOAST":
117 | if (action.toastId === undefined) {
118 | return {
119 | ...state,
120 | toasts: [],
121 | }
122 | }
123 | return {
124 | ...state,
125 | toasts: state.toasts.filter((t) => t.id !== action.toastId),
126 | }
127 | }
128 | }
129 |
130 | const listeners: Array<(state: State) => void> = []
131 |
132 | let memoryState: State = { toasts: [] }
133 |
134 | function dispatch(action: Action) {
135 | memoryState = reducer(memoryState, action)
136 | listeners.forEach((listener) => {
137 | listener(memoryState)
138 | })
139 | }
140 |
141 | type Toast = Omit
142 |
143 | function toast({ ...props }: Toast) {
144 | const id = genId()
145 |
146 | const update = (props: ToasterToast) =>
147 | dispatch({
148 | type: "UPDATE_TOAST",
149 | toast: { ...props, id },
150 | })
151 | const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
152 |
153 | dispatch({
154 | type: "ADD_TOAST",
155 | toast: {
156 | ...props,
157 | id,
158 | open: true,
159 | onOpenChange: (open) => {
160 | if (!open) dismiss()
161 | },
162 | },
163 | })
164 |
165 | return {
166 | id: id,
167 | dismiss,
168 | update,
169 | }
170 | }
171 |
172 | function useToast() {
173 | const [state, setState] = React.useState(memoryState)
174 |
175 | React.useEffect(() => {
176 | listeners.push(setState)
177 | return () => {
178 | const index = listeners.indexOf(setState)
179 | if (index > -1) {
180 | listeners.splice(index, 1)
181 | }
182 | }
183 | }, [state])
184 |
185 | return {
186 | ...state,
187 | toast,
188 | dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
189 | }
190 | }
191 |
192 | export { useToast, toast }
193 |
--------------------------------------------------------------------------------
/conf/db/nts.sql:
--------------------------------------------------------------------------------
1 | SET NAMES utf8mb4;
2 | SET FOREIGN_KEY_CHECKS = 0;
3 |
4 | -- ----------------------------
5 | -- Table structure for endpoints
6 | -- ----------------------------
7 | DROP TABLE IF EXISTS `endpoints`;
8 | CREATE TABLE `endpoints` (
9 | `id` bigint NOT NULL AUTO_INCREMENT,
10 | `type_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
11 | `type_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
12 | `type_schema` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
13 | `prompt` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
14 | `ctime` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
15 | PRIMARY KEY (`id`) USING BTREE,
16 | UNIQUE KEY `idx_tid` (`type_id`) USING BTREE
17 | ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
18 |
19 | -- ----------------------------
20 | -- Records of endpoints
21 | -- ----------------------------
22 | BEGIN;
23 | INSERT INTO `endpoints` (`id`, `type_id`, `type_name`, `type_schema`, `prompt`, `ctime`) VALUES (1, '132e14f5b3bdff04165449b37cad39ac', 'ShareOrNot', '// The following is a schema definition for determining whether a user wants to share a post or not:\n\nexport interface ShareOrNot {\n isShare: boolean;\n url: string;\n comment: string;\n}', 'https://github.com/shengxia/RWKV_Role_Playing_API 一个基于Flask实现的RWKV角色扮演API', NULL);
24 | INSERT INTO `endpoints` (`id`, `type_id`, `type_name`, `type_schema`, `prompt`, `ctime`) VALUES (2, 'dbd3c5e8b0d679fc81d33ff1f42a67e7', 'CustomerHouseRequest', '// 以下是客户的房屋需求数据结构定义:\nexport interface CustomerHouseRequest {\n area: string;\n roomCount: number;\n budget: string;\n floor: string;\n isContinueGuiding: boolean; // 是否需要继续引导,如果提取出的信息过少,需要继续引导\n nextQuestion: string; // 引导话术,如果isContinueGuiding为true,请生成引导话术\n}', '用户:找一个福道大厦附近的3居室\n经纪人:大概多少预算呀?\n用户:500万以内\n经纪人:对楼层有要求吗?\n用户:不要一层', NULL);
25 | INSERT INTO `endpoints` (`id`, `type_id`, `type_name`, `type_schema`, `prompt`, `ctime`) VALUES (3, 'b72eabec250a9707761516c12ef318b1', 'QuestionAnwserOrNot', '// 以下是判断输入内容是否是QA对的数据结构定义:\nexport interface QuestionAnwserOrNot {\n isQuestionAndAnwserContent: boolean;\n}', 'Q1: 出差乘坐火车票、飞机票的报销标准是什么?\nA: (1)火车硬卧及动车二等座可报销,包括因工作原因或不可抗力因素产生的退票及改签费用。火车商务座、一等座自费升级,公司不予报销升级费用。若火车二等座售罄且一等座不超过飞机票经济舱全价费用,留取相应证明资料后可选择火车一等座; ', NULL);
26 | INSERT INTO `endpoints` (`id`, `type_id`, `type_name`, `type_schema`, `prompt`, `ctime`) VALUES (4, '9f992b65d3899dbb54a19823db7dd25c', 'IntentRecognition', '// The following is the structural definition of intention recognition results.\n//\n// The intention value range descibed as bellow:\n// `share`: user want to share a link\n// `download`: user want to download something\n// `question`: user ask a question\n// `summarize`: user want to summarize something\n// `other`: user\'s intention is not clear\n//\n// If the intention is `other` or `question`, anwser for `user request` as an helpful assistant, and fill the `reply` field \nexport interface IntentRecognition {\n intention: string;\n reply: string;\n}', 'what\'s 1 plus 1', NULL);
27 | INSERT INTO `endpoints` (`id`, `type_id`, `type_name`, `type_schema`, `prompt`, `ctime`) VALUES (5, '67178ce98d7cb7e6314577b013e11f81', 'Person', '// The following is a schema definition for determining whether a user wants to share a post or not:\n\nexport interface Person {\n name: string;\n age: number;\n gender: string;\n hobby: string;\n job: string;\n}', '我叫田瑗,性别女,1990年出生,喜欢户外运动,职业与旅游相关', NULL);
28 | INSERT INTO `endpoints` (`id`, `type_id`, `type_name`, `type_schema`, `prompt`, `ctime`) VALUES (6, '334d7b8d15f795abac20fef697ae96b6', 'CalendarActions', '// The following types define the structure of an object of type CalendarActions that represents a list of requested calendar actions\n\nexport type CalendarActions = {\n actions: Action[];\n};\n\nexport type Action =\n | AddEventAction\n | RemoveEventAction\n | AddParticipantsAction\n | ChangeTimeRangeAction\n | ChangeDescriptionAction\n | FindEventsAction\n | UnknownAction;\n\nexport type AddEventAction = {\n actionType: \'add event\';\n event: Event;\n};\n\nexport type RemoveEventAction = {\n actionType: \'removeEvent\';\n eventReference: EventReference;\n};\n\nexport type AddParticipantsAction = {\n actionType: \'add participants\';\n // event to be augmented; if not specified assume last event discussed\n eventReference?: EventReference;\n // new participants (one or more)\n participants: string[];\n};\n\nexport type ChangeTimeRangeAction = {\n actionType: \'change time range\';\n // event to be changed\n eventReference?: EventReference;\n // new time range for the event\n timeRange: EventTimeRange;\n};\n\nexport type ChangeDescriptionAction = {\n actionType: \'change description\';\n // event to be changed\n eventReference?: EventReference;\n // new description for the event\n description: string;\n};\n\nexport type FindEventsAction = {\n actionType: \'find events\';\n // one or more event properties to use to search for matching events\n eventReference: EventReference;\n};\n\n// if the user types text that can not easily be understood as a calendar action, this action is used\nexport interface UnknownAction {\n actionType: \'unknown\';\n // text typed by the user that the system did not understand\n text: string;\n}\n\nexport type EventTimeRange = {\n startTime?: string;\n endTime?: string;\n duration?: string;\n};\n\nexport type Event = {\n // date (example: March 22, 2024) or relative date (example: after EventReference)\n day: string;\n timeRange: EventTimeRange;\n description: string;\n location?: string;\n // a list of people or named groups like \'team\'\n participants?: string[];\n};\n\n// properties used by the requester in referring to an event\n// these properties are only specified if given directly by the requester\nexport type EventReference = {\n // date (example: March 22, 2024) or relative date (example: after EventReference)\n day?: string;\n // (examples: this month, this week, in the next two days)\n dayRange?: string;\n timeRange?: EventTimeRange;\n description?: string;\n location?: string;\n participants?: string[];\n};\n', 'I need to get my tires changed from 12:00 to 2:00 pm on Friday March 15, 2024', NULL);
29 | INSERT INTO `endpoints` (`id`, `type_id`, `type_name`, `type_schema`, `prompt`, `ctime`) VALUES (7, '2dafcb4800ec144356799d5f4da07f32', 'SentimentResponse', 'export interface SentimentResponse {\n sentiment: \"negative\" | \"neutral\" | \"positive\"; // The sentiment of the text\n}\n', 'it\'s very rainy outside', NULL);
30 | INSERT INTO `endpoints` (`id`, `type_id`, `type_name`, `type_schema`, `prompt`, `ctime`) VALUES (8, '6a5269dc1455d181cedba3e806807431', 'Cart', '// The following is a schema definition for ordering lattes.\n\nexport interface Cart {\n items: (LineItem | UnknownText)[];\n}\n\n// Use this type for order items that match nothing else\nexport interface UnknownText {\n type: \'unknown\',\n text: string; // The text that wasn\'t understood\n}\n\nexport interface LineItem {\n type: \'lineitem\',\n product: Product;\n quantity: number;\n}\n\nexport type Product = BakeryProducts | LatteDrinks | EspressoDrinks | CoffeeDrinks;\n\nexport interface BakeryProducts {\n type: \'BakeryProducts\';\n name: \'apple bran muffin\' | \'blueberry muffin\' | \'lemon poppyseed muffin\' | \'bagel\';\n options: (BakeryOptions | BakeryPreparations)[];\n}\n\nexport interface BakeryOptions {\n type: \'BakeryOptions\';\n name: \'butter\' | \'strawberry jam\' | \'cream cheese\';\n optionQuantity?: OptionQuantity;\n}\n\nexport interface BakeryPreparations {\n type: \'BakeryPreparations\';\n name: \'warmed\' | \'cut in half\';\n}\n\nexport interface LatteDrinks {\n type: \'LatteDrinks\';\n name: \'cappuccino\' | \'flat white\' | \'latte\' | \'latte macchiato\' | \'mocha\' | \'chai latte\';\n temperature?: CoffeeTemperature;\n size?: CoffeeSize; // The default is \'grande\'\n options?: (Milks | Sweeteners | Syrups | Toppings | Caffeines | LattePreparations)[];\n}\n\nexport interface EspressoDrinks {\n type: \'EspressoDrinks\';\n name: \'espresso\' | \'lungo\' | \'ristretto\' | \'macchiato\';\n temperature?: CoffeeTemperature;\n size?: EspressoSize; // The default is \'doppio\'\n options?: (Creamers | Sweeteners | Syrups | Toppings | Caffeines | LattePreparations)[];\n}\n\nexport interface CoffeeDrinks {\n type: \'CoffeeDrinks\';\n name: \'americano\' | \'coffee\';\n temperature?: CoffeeTemperature;\n size?: CoffeeSize; // The default is \'grande\'\n options?: (Creamers | Sweeteners | Syrups | Toppings | Caffeines | LattePreparations)[];\n}\n\nexport interface Syrups {\n type: \'Syrups\';\n name: \'almond syrup\' | \'buttered rum syrup\' | \'caramel syrup\' | \'cinnamon syrup\' | \'hazelnut syrup\' |\n \'orange syrup\' | \'peppermint syrup\' | \'raspberry syrup\' | \'toffee syrup\' | \'vanilla syrup\';\n optionQuantity?: OptionQuantity;\n}\n\nexport interface Caffeines {\n type: \'Caffeines\';\n name: \'regular\' | \'two thirds caf\' | \'half caf\' | \'one third caf\' | \'decaf\';\n}\n\nexport interface Milks {\n type: \'Milks\';\n name: \'whole milk\' | \'two percent milk\' | \'nonfat milk\' | \'coconut milk\' | \'soy milk\' | \'almond milk\' | \'oat milk\';\n}\n\nexport interface Creamers {\n type: \'Creamers\';\n name: \'whole milk creamer\' | \'two percent milk creamer\' | \'one percent milk creamer\' | \'nonfat milk creamer\' |\n \'coconut milk creamer\' | \'soy milk creamer\' | \'almond milk creamer\' | \'oat milk creamer\' | \'half and half\' |\n \'heavy cream\';\n}\n\nexport interface Toppings {\n type: \'Toppings\';\n name: \'cinnamon\' | \'foam\' | \'ice\' | \'nutmeg\' | \'whipped cream\' | \'water\';\n optionQuantity?: OptionQuantity;\n}\n\nexport interface LattePreparations {\n type: \'LattePreparations\';\n name: \'for here cup\' | \'lid\' | \'with room\' | \'to go\' | \'dry\' | \'wet\';\n}\n\nexport interface Sweeteners {\n type: \'Sweeteners\';\n name: \'equal\' | \'honey\' | \'splenda\' | \'sugar\' | \'sugar in the raw\' | \'sweet n low\' | \'espresso shot\';\n optionQuantity?: OptionQuantity;\n}\n\nexport type CoffeeTemperature = \'hot\' | \'extra hot\' | \'warm\' | \'iced\';\n\nexport type CoffeeSize = \'short\' | \'tall\' | \'grande\' | \'venti\';\n\nexport type EspressoSize = \'solo\' | \'doppio\' | \'triple\' | \'quad\';\n\nexport type OptionQuantity = \'no\' | \'light\' | \'regular\' | \'extra\' | number;\n', 'two tall lattes. the first one with no foam. the second one with whole milk.', NULL);
31 | INSERT INTO `endpoints` (`id`, `type_id`, `type_name`, `type_schema`, `prompt`, `ctime`) VALUES (9, '3d4e92513d75c28f02637be1450fc3dc', 'Order', '// an order from a restaurant that serves pizza, beer, and salad\nexport type Order = {\n items: (OrderItem | UnknownText)[];\n};\n\nexport type OrderItem = Pizza | Beer | Salad | NamedPizza;\n\n// Use this type for order items that match nothing else\nexport interface UnknownText {\n itemType: \'unknown\',\n text: string; // The text that wasn\'t understood\n}\n\n\nexport type Pizza = {\n itemType: \'pizza\';\n // default: large\n size?: \'small\' | \'medium\' | \'large\' | \'extra large\';\n // toppings requested (examples: pepperoni, arugula)\n addedToppings?: string[];\n // toppings requested to be removed (examples: fresh garlic, anchovies)\n removedToppings?: string[];\n // default: 1\n quantity?: number;\n // used if the requester references a pizza by name\n name?: \"Hawaiian\" | \"Yeti\" | \"Pig In a Forest\" | \"Cherry Bomb\";\n};\n\nexport interface NamedPizza extends Pizza {\n}\n\nexport type Beer = {\n itemType: \'beer\';\n // examples: Mack and Jacks, Sierra Nevada Pale Ale, Miller Lite\n kind: string;\n // default: 1\n quantity?: number;\n};\n\nexport const saladSize = [\'half\', \'whole\'];\n\nexport const saladStyle = [\'Garden\', \'Greek\'];\n\nexport type Salad = {\n itemType: \'salad\';\n // default: half\n portion?: string;\n // default: Garden\n style?: string;\n // ingredients requested (examples: parmesan, croutons)\n addedIngredients?: string[];\n // ingredients requested to be removed (example: red onions)\n removedIngredients?: string[];\n // default: 1\n quantity?: number;\n};\n\n', 'I\'d like two large, one with pepperoni and the other with extra sauce. The pepperoni gets basil and the extra sauce gets Canadian bacon. And add a whole salad. Make the Canadian bacon a medium. Make the salad a Greek with no red onions. And give me two Mack and Jacks and a Sierra Nevada. Oh, and add another salad with no red onions.', NULL);
32 | COMMIT;
33 |
34 | SET FOREIGN_KEY_CHECKS = 1;
35 |
--------------------------------------------------------------------------------
/lib/db.ts:
--------------------------------------------------------------------------------
1 | import mysql from "serverless-mysql";
2 | import mysql2 from "mysql2";
3 |
4 | export const db = mysql({
5 | config: {
6 | host: process.env.MYSQL_HOST,
7 | port: parseInt(process.env.MYSQL_PORT!),
8 | database: process.env.MYSQL_DATABASE,
9 | user: process.env.MYSQL_USERNAME,
10 | password: process.env.MYSQL_PASSWORD,
11 | insecureAuth: true,
12 | },
13 | library: mysql2 as unknown as Function,
14 | });
15 |
16 | export interface QueryParams {
17 | query: string;
18 | values?: any[];
19 | }
20 |
21 | export interface DBError {
22 | error: any;
23 | code: string;
24 | errno: number;
25 | sqlMessage: string;
26 | sqlState: string;
27 | sql: string;
28 | }
29 |
30 | export async function executeQuery({ query, values }: QueryParams) {
31 | try {
32 | const results = await db.query(query, values);
33 | await db.end();
34 | return results;
35 | } catch (error) {
36 | return {error};
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 | import crypto from "crypto"
4 |
5 | export function cn(...inputs: ClassValue[]) {
6 | return twMerge(clsx(inputs))
7 | }
8 |
9 | export function md5sum(text: string) {
10 | const md5 = crypto.createHash('md5');
11 | return md5.update(text).digest('hex')
12 | }
13 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {}
3 |
4 | module.exports = nextConfig
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "json-translator",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@radix-ui/react-slot": "^1.0.2",
13 | "@radix-ui/react-toast": "^1.1.4",
14 | "@types/node": "20.4.4",
15 | "@types/react-dom": "18.2.7",
16 | "@uiw/react-textarea-code-editor": "^2.1.7",
17 | "autoprefixer": "10.4.14",
18 | "class-variance-authority": "^0.7.0",
19 | "clsx": "^2.0.0",
20 | "eslint": "8.45.0",
21 | "eslint-config-next": "13.4.12",
22 | "googleapis": "^122.0.0",
23 | "lucide-react": "^0.263.1",
24 | "mysql2": "^3.5.2",
25 | "next": "13.4.12",
26 | "postcss": "8.4.27",
27 | "react": "^18.2.0",
28 | "react-dom": "^18.2.0",
29 | "react-loader-spinner": "^5.3.4",
30 | "serverless-mysql": "^1.5.5",
31 | "tailwind-merge": "^1.14.0",
32 | "tailwindcss": "3.3.3",
33 | "tailwindcss-animate": "^1.0.6",
34 | "typechat": "0.0.10",
35 | "typescript": "5.1.6"
36 | },
37 | "devDependencies": {
38 | "@types/react": "^18.2.15"
39 | },
40 | "engines": {
41 | "node": "^18"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/snapshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cooder-org/json-translator/db4132782f79b12fcca068985df3fa67d2bd86b3/public/snapshot.png
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | darkMode: ["class"],
4 | content: [
5 | './pages/**/*.{ts,tsx}',
6 | './components/**/*.{ts,tsx}',
7 | './app/**/*.{ts,tsx}',
8 | './src/**/*.{ts,tsx}',
9 | ],
10 | theme: {
11 | container: {
12 | center: true,
13 | padding: "2rem",
14 | screens: {
15 | "2xl": "1400px",
16 | },
17 | },
18 | extend: {
19 | colors: {
20 | border: "hsl(var(--border))",
21 | input: "hsl(var(--input))",
22 | ring: "hsl(var(--ring))",
23 | background: "hsl(var(--background))",
24 | foreground: "hsl(var(--foreground))",
25 | primary: {
26 | DEFAULT: "hsl(var(--primary))",
27 | foreground: "hsl(var(--primary-foreground))",
28 | },
29 | secondary: {
30 | DEFAULT: "hsl(var(--secondary))",
31 | foreground: "hsl(var(--secondary-foreground))",
32 | },
33 | destructive: {
34 | DEFAULT: "hsl(var(--destructive))",
35 | foreground: "hsl(var(--destructive-foreground))",
36 | },
37 | muted: {
38 | DEFAULT: "hsl(var(--muted))",
39 | foreground: "hsl(var(--muted-foreground))",
40 | },
41 | accent: {
42 | DEFAULT: "hsl(var(--accent))",
43 | foreground: "hsl(var(--accent-foreground))",
44 | },
45 | popover: {
46 | DEFAULT: "hsl(var(--popover))",
47 | foreground: "hsl(var(--popover-foreground))",
48 | },
49 | card: {
50 | DEFAULT: "hsl(var(--card))",
51 | foreground: "hsl(var(--card-foreground))",
52 | },
53 | },
54 | borderRadius: {
55 | lg: "var(--radius)",
56 | md: "calc(var(--radius) - 2px)",
57 | sm: "calc(var(--radius) - 4px)",
58 | },
59 | keyframes: {
60 | "accordion-down": {
61 | from: { height: 0 },
62 | to: { height: "var(--radix-accordion-content-height)" },
63 | },
64 | "accordion-up": {
65 | from: { height: "var(--radix-accordion-content-height)" },
66 | to: { height: 0 },
67 | },
68 | },
69 | animation: {
70 | "accordion-down": "accordion-down 0.2s ease-out",
71 | "accordion-up": "accordion-up 0.2s ease-out",
72 | },
73 | },
74 | },
75 | plugins: [require("tailwindcss-animate")],
76 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "bundler",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "plugins": [
18 | {
19 | "name": "next"
20 | }
21 | ],
22 | "paths": {
23 | "@/*": ["./*"]
24 | }
25 | },
26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
27 | "exclude": ["node_modules"]
28 | }
29 |
--------------------------------------------------------------------------------