-
Notifications
You must be signed in to change notification settings - Fork 4
Move llm-api endpoints to vercel serverless #102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
4df05ea
testing gemini
sid597 0bd5ee8
move endgoint to website
sid597 e61d221
open ai endpoint
sid597 331cd10
added anthropic endpoint
sid597 b3d8257
pass env vars
sid597 ed6c5b2
add cors handdling and options
sid597 487f3e2
.
sid597 2a1471d
using centralised cors middleware
sid597 259ff33
only adding bypass cookie
sid597 dd5a687
use right key
sid597 cc96752
remove the bypass token requirement
sid597 a5f7276
sanitize, fix routes
sid597 413988b
remove server action config
sid597 2b99736
DRY
sid597 d529174
remove unused
sid597 c2a2c91
address review
sid597 04c1c6c
adress review
sid597 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
DRY
- Loading branch information
commit 2b99736b0ecc0f4b72ed6fb01be1fc2115a1fa45
There are no files selected for viewing
This file contains hidden or 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 |
|---|---|---|
| @@ -1,143 +1,18 @@ | ||
| import { NextRequest } from "next/server"; | ||
| import cors from "../../../../../lib/cors"; | ||
|
|
||
| type Message = { | ||
| role: string; | ||
| content: string; | ||
| }; | ||
|
|
||
| type Settings = { | ||
| model: string; | ||
| maxTokens: number; | ||
| temperature: number; | ||
| }; | ||
|
|
||
| type AnthropicUsage = { | ||
| input_tokens: number; | ||
| output_tokens: number; | ||
| }; | ||
|
|
||
| type RequestBody = { | ||
| documents: Message[]; | ||
| passphrase?: string; | ||
| settings: Settings; | ||
| }; | ||
|
|
||
| const CONTENT_TYPE_JSON = "application/json"; | ||
| const CONTENT_TYPE_TEXT = "text/plain"; | ||
| const ANTHROPIC_API_VERSION = "2023-06-01"; | ||
| import { | ||
| handleLLMRequest, | ||
| handleOptionsRequest, | ||
| } from "../../../../../lib/llm/handler"; | ||
| import { anthropicConfig } from "../../../../../lib/llm/providers"; | ||
sid597 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| export const runtime = "nodejs"; | ||
| export const preferredRegion = "auto"; | ||
| export const maxDuration = 300; | ||
|
|
||
| export async function POST(request: NextRequest): Promise<Response> { | ||
sid597 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| try { | ||
| const requestData: RequestBody = await request.json(); | ||
| const { documents: messages, settings } = requestData; | ||
| const { model, maxTokens, temperature } = settings; | ||
|
|
||
| const apiKey = process.env.ANTHROPIC_API_KEY; | ||
|
|
||
| if (!apiKey) { | ||
| console.error("ANTHROPIC_API_KEY environment variable is not set"); | ||
| return cors( | ||
| request, | ||
| new Response( | ||
| JSON.stringify({ | ||
| error: | ||
| "API key not configured. Please set the ANTHROPIC_API_KEY environment variable in your Vercel project settings.", | ||
| }), | ||
| { | ||
| status: 500, | ||
| headers: { "Content-Type": CONTENT_TYPE_JSON }, | ||
| }, | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| const url = "https://api.anthropic.com/v1/messages"; | ||
|
|
||
| const body = JSON.stringify({ | ||
| model: model, | ||
| max_tokens: maxTokens, | ||
| messages: messages, | ||
| temperature: temperature, | ||
| }); | ||
|
|
||
| const response = await fetch(url, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": CONTENT_TYPE_JSON, | ||
| "x-api-key": apiKey, | ||
| "anthropic-version": ANTHROPIC_API_VERSION, | ||
| }, | ||
| body, | ||
| }); | ||
|
|
||
| const responseData = await response.json(); | ||
|
|
||
| if (!response.ok) { | ||
| console.error("Anthropic API error:", responseData); | ||
| return cors( | ||
| request, | ||
| new Response( | ||
| JSON.stringify({ | ||
| error: `Anthropic API error: ${responseData.error?.message || "Unknown error"}`, | ||
| }), | ||
| { | ||
| status: response.status, | ||
| headers: { "Content-Type": CONTENT_TYPE_JSON }, | ||
| }, | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| const replyText = responseData.content?.[0]?.text; | ||
|
|
||
| if (!replyText) { | ||
| console.error( | ||
| "Invalid response format from Anthropic API:", | ||
| responseData, | ||
| ); | ||
| return cors( | ||
| request, | ||
| new Response( | ||
| JSON.stringify({ | ||
| error: | ||
| "Invalid response format from Anthropic API. Check server logs for details.", | ||
| }), | ||
| { | ||
| status: 500, | ||
| headers: { "Content-Type": CONTENT_TYPE_JSON }, | ||
| }, | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| return cors( | ||
| request, | ||
| new Response(replyText, { | ||
| headers: { "Content-Type": CONTENT_TYPE_TEXT }, | ||
| }), | ||
| ); | ||
| } catch (error) { | ||
| console.error("Error processing request:", error); | ||
| return cors( | ||
| request, | ||
| new Response( | ||
| JSON.stringify({ | ||
| error: `Internal Server Error: ${error instanceof Error ? error.message : "Unknown error"}`, | ||
| }), | ||
| { | ||
| status: 500, | ||
| headers: { "Content-Type": CONTENT_TYPE_JSON }, | ||
| }, | ||
| ), | ||
| ); | ||
| } | ||
| return handleLLMRequest(request, anthropicConfig); | ||
| } | ||
|
|
||
| export async function OPTIONS(request: NextRequest) { | ||
| return cors(request, new Response(null, { status: 204 })); | ||
| export async function OPTIONS(request: NextRequest): Promise<Response> { | ||
| return handleOptionsRequest(request); | ||
| } | ||
This file contains hidden or 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 |
|---|---|---|
| @@ -1,152 +1,18 @@ | ||
| import { NextRequest } from "next/server"; | ||
| import cors from "../../../../../lib/cors"; | ||
|
|
||
| type Message = { | ||
| role: string; | ||
| content: string; | ||
| }; | ||
|
|
||
| type Settings = { | ||
| model: string; | ||
| maxTokens: number; | ||
| temperature: number; | ||
| safetySettings?: Array<{ | ||
| category: string; | ||
| threshold: string; | ||
| }>; | ||
| }; | ||
|
|
||
| type RequestBody = { | ||
| documents: Message[]; | ||
| passphrase?: string; | ||
| settings: Settings; | ||
| }; | ||
|
|
||
| type GeminiMessage = { | ||
| role: string; | ||
| parts: Array<{ | ||
| text: string; | ||
| }>; | ||
| }; | ||
|
|
||
| const CONTENT_TYPE_JSON = "application/json"; | ||
| const CONTENT_TYPE_TEXT = "text/plain"; | ||
| import { | ||
| handleLLMRequest, | ||
| handleOptionsRequest, | ||
| } from "../../../../../lib/llm/handler"; | ||
sid597 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| import { geminiConfig } from "../../../../../lib/llm/providers"; | ||
sid597 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| export const runtime = "nodejs"; | ||
| export const preferredRegion = "auto"; | ||
| export const maxDuration = 300; | ||
|
|
||
| function convertToGeminiFormat(messages: Message[]): GeminiMessage[] { | ||
| return messages.map((msg) => ({ | ||
| role: msg.role === "user" ? "user" : "model", | ||
| parts: [{ text: msg.content }], | ||
| })); | ||
| } | ||
|
|
||
| export async function POST(request: NextRequest): Promise<Response> { | ||
| try { | ||
| const requestData: RequestBody = await request.json(); | ||
| const { documents: messages, settings } = requestData; | ||
| const { model, maxTokens, temperature } = settings; | ||
|
|
||
| const apiKey = process.env.GEMINI_API_KEY; | ||
|
|
||
| if (!apiKey) { | ||
| console.error("GEMINI_API_KEY environment variable is not set"); | ||
| return cors( | ||
| request, | ||
| new Response( | ||
| JSON.stringify({ | ||
| error: | ||
| "API key not configured. Please set the GEMINI_API_KEY environment variable in your Vercel project settings.", | ||
| }), | ||
| { | ||
| status: 500, | ||
| headers: { "Content-Type": CONTENT_TYPE_JSON }, | ||
| }, | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`; | ||
|
|
||
| const body = JSON.stringify({ | ||
| contents: convertToGeminiFormat(messages), | ||
| generationConfig: { | ||
| maxOutputTokens: maxTokens, | ||
| temperature: temperature, | ||
| }, | ||
| safetySettings: settings.safetySettings, | ||
| }); | ||
|
|
||
| const response = await fetch(url, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": CONTENT_TYPE_JSON, | ||
| }, | ||
| body, | ||
| }); | ||
|
|
||
| const responseData = await response.json(); | ||
|
|
||
| if (!response.ok) { | ||
| console.error("Gemini API error:", responseData); | ||
| return cors( | ||
| request, | ||
| new Response( | ||
| JSON.stringify({ | ||
| error: `Gemini API error: ${responseData.error?.message || "Unknown error"}`, | ||
| }), | ||
| { | ||
| status: response.status, | ||
| headers: { "Content-Type": CONTENT_TYPE_JSON }, | ||
| }, | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| const replyText = responseData.candidates?.[0]?.content?.parts?.[0]?.text; | ||
|
|
||
| if (!replyText) { | ||
| console.error("Invalid response format from Gemini API:", responseData); | ||
| return cors( | ||
| request, | ||
| new Response( | ||
| JSON.stringify({ | ||
| error: | ||
| "Invalid response format from Gemini API. Check server logs for details.", | ||
| }), | ||
| { | ||
| status: 500, | ||
| headers: { "Content-Type": CONTENT_TYPE_JSON }, | ||
| }, | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| return cors( | ||
| request, | ||
| new Response(replyText, { | ||
| headers: { "Content-Type": CONTENT_TYPE_TEXT }, | ||
| }), | ||
| ); | ||
| } catch (error) { | ||
| console.error("Error processing request:", error); | ||
| return cors( | ||
| request, | ||
| new Response( | ||
| JSON.stringify({ | ||
| error: `Internal Server Error: ${error instanceof Error ? error.message : "Unknown error"}`, | ||
| }), | ||
| { | ||
| status: 500, | ||
| headers: { "Content-Type": CONTENT_TYPE_JSON }, | ||
| }, | ||
| ), | ||
| ); | ||
| } | ||
| return handleLLMRequest(request, geminiConfig); | ||
| } | ||
|
|
||
| export async function OPTIONS(request: NextRequest) { | ||
| return cors(request, new Response(null, { status: 204 })); | ||
| export async function OPTIONS(request: NextRequest): Promise<Response> { | ||
| return handleOptionsRequest(request); | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.