-
Notifications
You must be signed in to change notification settings - Fork 1
Fix the entire codebase 🇫🇮 #17
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 all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
a608f00
fix auth look
alexechoi 0d9ce39
fix routing for cached
alexechoi 148d39e
add landing page carry through for the prompt area
alexechoi 14d7528
update the footer
alexechoi 42aed5f
fix copilot
alexechoi 4eac8d0
remove redundant nav items
alexechoi 8d32028
share and export
alexechoi 11e9851
format
alexechoi 94a2504
Merge branch 'main' into alex/fixes
alexechoi 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
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 |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| import { ai } from "@/lib/gemini"; | ||
| import { adminDb } from "@/lib/firebase-admin"; | ||
|
|
||
| export async function POST( | ||
| request: Request, | ||
| { params }: { params: Promise<{ id: string }> }, | ||
| ) { | ||
| try { | ||
| const { id } = await params; | ||
| const { question } = await request.json(); | ||
|
|
||
| if (!id) { | ||
| return Response.json({ error: "Report ID is required" }, { status: 400 }); | ||
| } | ||
|
|
||
| if (!question || typeof question !== "string") { | ||
| return Response.json( | ||
| { error: "Question is required and must be a string" }, | ||
| { status: 400 }, | ||
| ); | ||
| } | ||
|
|
||
| const cacheDoc = await adminDb | ||
| .collection("cache") | ||
| .doc(id.toLowerCase()) | ||
| .get(); | ||
|
|
||
| if (!cacheDoc.exists) { | ||
| return Response.json( | ||
| { error: "Report not found", id: id.toLowerCase() }, | ||
| { status: 404 }, | ||
| ); | ||
| } | ||
|
|
||
| const docData = cacheDoc.data(); | ||
| const contextPayload = { | ||
| id: cacheDoc.id, | ||
| cached_at: docData?.cached_at ?? null, | ||
| query: docData?.query ?? id, | ||
| report: docData?.report ?? null, | ||
| }; | ||
|
|
||
| const result = await ai.models.generateContent({ | ||
| model: "gemini-2.0-flash-exp", | ||
| contents: [ | ||
| { | ||
| role: "user", | ||
| parts: [ | ||
| { | ||
| text: `You are an expert security analyst. Rely ONLY on the context provided below when answering the user's question. | ||
| If the context does not contain the requested information, reply exactly with "I don't have information about that in this report." | ||
| Do not speculate, hallucinate, or reference external knowledge. Keep answers to 2-4 concise sentences and reference concrete values from the context when available. | ||
|
|
||
| Context (JSON): | ||
| ${JSON.stringify(contextPayload, null, 2)} | ||
|
|
||
| Question: ${question}`, | ||
| }, | ||
| ], | ||
| }, | ||
| ], | ||
| }); | ||
|
|
||
| const answer = result.text?.trim(); | ||
|
|
||
| if (!answer) { | ||
| return Response.json( | ||
| { error: "The analyst could not generate an answer." }, | ||
| { status: 502 }, | ||
| ); | ||
| } | ||
|
|
||
| return Response.json({ | ||
| answer, | ||
| reportId: cacheDoc.id, | ||
| question, | ||
| }); | ||
| } catch (error) { | ||
| console.error("Error answering report question:", error); | ||
| return Response.json( | ||
| { | ||
| error: "Internal server error", | ||
| details: error instanceof Error ? error.message : "Unknown error", | ||
| }, | ||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } |
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
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Runtime TypeError when non-string values are processed. The code filters possibleCacheIds from matchedEntity properties (cacheId, cache_id, id, name, etc.) using .filter(Boolean), which only removes falsy values but does NOT guarantee the remaining values are strings. Since matchedEntity is typed as Record<string, any> and populated from untyped Firestore data, these fields could be numbers, objects, arrays, or other non-string types. The type annotation (value: string) is merely a type assertion and does not perform runtime validation. When .toLowerCase() is called on a non-string value, it will throw: TypeError: value.toLowerCase is not a function. This will crash the API endpoint when triggered by Firestore data containing non-string cache ID fields. To fix, convert values to strings before calling toLowerCase(): .map((value) => String(value).toLowerCase())