-
-
Notifications
You must be signed in to change notification settings - Fork 268
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
439 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
app/ui/src/components/Bot/Integration/API/ApiPlaygroundComponent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const ApiPlaygroundComponent: React.FC = () => { | ||
return ( | ||
<div className=" min-h-screen "> | ||
<div className="border rounded-md p-4 max-w-screen-xl mx-auto"> | ||
<h1 className="text-xl font-bold mb-4">POST /chat/completions</h1> | ||
|
||
<div className="grid sm:grid-cols-1 md:grid-cols-2 gap-4"> | ||
<div className="border rounded-md p-4"> | ||
<h2 className="text-lg font-semibold mb-2">LEFT PANEL</h2> | ||
{/* Content of left panel */} | ||
</div> | ||
|
||
<div className="border rounded-md p-4"> | ||
<h2 className="text-lg font-semibold mb-2">RIGHT PANEL</h2> | ||
{/* Content of right panel */} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
|
||
export default ApiPlaygroundComponent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React from "react"; | ||
import NoApiKeyComponent from "./NoApiKeyComponent"; | ||
import { BotIntegrationAPI } from "../../../../@types/bot"; | ||
import ApiPlaygroundComponent from "./ApiPlaygroundComponent"; | ||
|
||
const IntegrationAPIBody: React.FC<BotIntegrationAPI> = ({ | ||
is_api_enabled, | ||
}) => { | ||
return ( | ||
<div className="p-4"> | ||
<h2 className="text-2xl font-semibold mb-4 text-left">API Integration</h2> | ||
{!is_api_enabled && <NoApiKeyComponent />} | ||
{is_api_enabled && <ApiPlaygroundComponent />} | ||
</div> | ||
); | ||
}; | ||
|
||
export default IntegrationAPIBody; |
52 changes: 52 additions & 0 deletions
52
app/ui/src/components/Bot/Integration/API/NoApiKeyComponent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { useMutation, useQueryClient } from "@tanstack/react-query"; | ||
import { notification } from "antd"; | ||
import React from "react"; | ||
import api from "../../../../services/api"; | ||
import { useParams } from "react-router-dom"; | ||
|
||
const NoApiKeyComponent: React.FC = () => { | ||
const client = useQueryClient(); | ||
const param = useParams<{ id: string }>(); | ||
const { mutate: generateAPIKey, isLoading: isGeneratingAPIKey } = useMutation( | ||
async () => { | ||
const response = await api.post(`/bot/integration/${param.id}/api`); | ||
return response.data; | ||
}, | ||
{ | ||
onSuccess: () => { | ||
notification.success({ | ||
message: "Success", | ||
description: "API key generated successfully.", | ||
}); | ||
client.invalidateQueries(["getBotIntegrationAPI"]); | ||
}, | ||
onError: (e) => { | ||
console.log(e); | ||
notification.error({ | ||
message: "Error", | ||
description: "Something went wrong while generating the API key.", | ||
}); | ||
}, | ||
} | ||
); | ||
|
||
return ( | ||
<div className="m-0 p-0 h-screen flex flex-col justify-start items-center"> | ||
<div className="mt-20 p-8 border bg-gray-50 border-gray-300 rounded-lg"> | ||
<h1 className="text-2xl font-semibold mb-4">No API Key Found</h1> | ||
<p className="mb-4">You need to generate an API key to get started.</p> | ||
<button | ||
disabled={isGeneratingAPIKey} | ||
onClick={() => { | ||
generateAPIKey(); | ||
}} | ||
className="bg-indigo-600 w-full text-center text-white px-4 py-2 rounded hover:bg-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-300 disabled:opacity-50 disabled:cursor-not-allowed" | ||
> | ||
{!isGeneratingAPIKey ? "Generate API Key" : "Generating API Key..."} | ||
</button> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default NoApiKeyComponent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { useQuery } from "@tanstack/react-query"; | ||
import React from "react"; | ||
import { useNavigate, useParams } from "react-router-dom"; | ||
import api from "../../services/api"; | ||
import { SkeletonLoading } from "../../components/Common/SkeletonLoading"; | ||
import IntegrationAPIBody from "../../components/Bot/Integration/API/Index"; | ||
import { BotIntegrationAPI } from "../../@types/bot"; | ||
|
||
export default function BotIntegrationAPIRoot() { | ||
const param = useParams<{ id: string }>(); | ||
const navigate = useNavigate(); | ||
const { data, status } = useQuery( | ||
["getBotIntegrationAPI", param.id], | ||
async () => { | ||
const response = await api.get(`/bot/integration/${param.id}/api`); | ||
return response.data as BotIntegrationAPI; | ||
}, | ||
{ | ||
enabled: !!param.id, | ||
} | ||
); | ||
|
||
React.useEffect(() => { | ||
if (status === "error") { | ||
navigate("/"); | ||
} | ||
}, [status]); | ||
|
||
return ( | ||
<div className="mx-auto my-3 w-full max-w-7xl"> | ||
{status === "loading" && | ||
|
||
<SkeletonLoading /> | ||
|
||
} | ||
{status === "success" && <IntegrationAPIBody {...data} />} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
server/src/routes/api/v1/bot/integration/handlers/api.handler.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import { FastifyReply, FastifyRequest } from "fastify"; | ||
import { GetAPIIntergationRequest } from "./type"; | ||
import { randomBytes } from "crypto"; | ||
|
||
const generateAPIKey = (length = 32) => { | ||
const charset = | ||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | ||
const bytes = randomBytes(length); | ||
let result = ""; | ||
|
||
for (let i = 0; i < length; i++) { | ||
result += charset.charAt(bytes[i] % charset.length); | ||
} | ||
|
||
return result; | ||
}; | ||
|
||
export const getAPIIntegrationHandler = async ( | ||
request: FastifyRequest<GetAPIIntergationRequest>, | ||
reply: FastifyReply, | ||
) => { | ||
try { | ||
const prisma = request.server.prisma; | ||
const id = request.params.id; | ||
|
||
const bot = await prisma.bot.findFirst({ | ||
where: { | ||
id, | ||
user_id: request.user.user_id, | ||
}, | ||
}); | ||
|
||
if (!bot) { | ||
return reply.status(404).send({ | ||
message: "Bot not found", | ||
}); | ||
} | ||
|
||
if (!bot.bot_api_key) { | ||
return { | ||
is_api_enabled: false, | ||
data: { | ||
public_url: null, | ||
api_key: null, | ||
}, | ||
}; | ||
} | ||
|
||
return { | ||
is_api_enabled: true, | ||
data: { | ||
public_url: bot.publicId, | ||
api_key: bot.bot_api_key, | ||
}, | ||
}; | ||
} catch (e) { | ||
console.log(e); | ||
return reply.status(500).send({ message: "Internal Server Error" }); | ||
} | ||
}; | ||
|
||
export const generateAPIKeyHandler = async ( | ||
request: FastifyRequest<GetAPIIntergationRequest>, | ||
reply: FastifyReply, | ||
) => { | ||
try { | ||
const prisma = request.server.prisma; | ||
const id = request.params.id; | ||
|
||
const bot = await prisma.bot.findFirst({ | ||
where: { | ||
id, | ||
user_id: request.user.user_id, | ||
}, | ||
}); | ||
|
||
if (!bot) { | ||
return reply.status(404).send({ | ||
message: "Bot not found", | ||
}); | ||
} | ||
|
||
const bot_api_key = generateAPIKey(); | ||
|
||
await prisma.bot.update({ | ||
where: { | ||
id, | ||
}, | ||
data: { | ||
bot_api_key, | ||
}, | ||
}); | ||
|
||
return { | ||
data: { | ||
bot_api_key, | ||
}, | ||
}; | ||
} catch (e) { | ||
console.log(e); | ||
return reply.status(500).send({ message: "Internal Server Error" }); | ||
} | ||
}; | ||
|
||
export const regenerateAPIKeyHandler = async ( | ||
request: FastifyRequest<GetAPIIntergationRequest>, | ||
reply: FastifyReply, | ||
) => { | ||
try { | ||
const prisma = request.server.prisma; | ||
const id = request.params.id; | ||
|
||
const bot = await prisma.bot.findFirst({ | ||
where: { | ||
id, | ||
user_id: request.user.user_id, | ||
}, | ||
}); | ||
|
||
if (!bot) { | ||
return reply.status(404).send({ | ||
message: "Bot not found", | ||
}); | ||
} | ||
|
||
const bot_api_key = generateAPIKey(); | ||
|
||
await prisma.bot.update({ | ||
where: { | ||
id, | ||
}, | ||
data: { | ||
bot_api_key, | ||
}, | ||
}); | ||
|
||
return { | ||
data: { | ||
bot_api_key, | ||
}, | ||
}; | ||
} catch (e) { | ||
console.log(e); | ||
return reply.status(500).send({ message: "Internal Server Error" }); | ||
} | ||
}; |
Oops, something went wrong.