Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
GITHUB_WEBHOOK_SECRET=
GITHUB_TOKEN=
REPO_NAME= #Enter repo from where you want to fetch issues
SIMILARITY_THRESHOLD=
MY_REPO_NAME= #Enter repo for which you want to use

GITHUB_TOKEN=your_token_here
GITHUB_WEBHOOK_SECRET=your_secret_here
REPO_NAME=OpenLake/your-repo
TARGET_REPO=your-test-repo
SIMILARITY_THRESHOLD=0.85
Comment on lines +1 to +11

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Align the example with the actual env contract.

This file has two conflicting key blocks, and it never documents SOURCE_REPO, which app/config.py reads. New contributors will copy an incomplete/ambiguous config.

♻️ Suggested cleanup
-GITHUB_WEBHOOK_SECRET=
-GITHUB_TOKEN=
-REPO_NAME= `#Enter` repo from where you want to fetch issues
-SIMILARITY_THRESHOLD=
-MY_REPO_NAME= `#Enter` repo for which you want to use 
-
 GITHUB_TOKEN=your_token_here
 GITHUB_WEBHOOK_SECRET=your_secret_here
-REPO_NAME=OpenLake/your-repo
+SOURCE_REPO=OpenLake/your-repo
 TARGET_REPO=your-test-repo
 SIMILARITY_THRESHOLD=0.85

As per the app/config.py snippet, the app loads GITHUB_WEBHOOK_SECRET, GITHUB_TOKEN, TARGET_REPO, SIMILARITY_THRESHOLD, and SOURCE_REPO.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
GITHUB_WEBHOOK_SECRET=
GITHUB_TOKEN=
REPO_NAME= #Enter repo from where you want to fetch issues
SIMILARITY_THRESHOLD=
MY_REPO_NAME= #Enter repo for which you want to use
GITHUB_TOKEN=your_token_here
GITHUB_WEBHOOK_SECRET=your_secret_here
REPO_NAME=OpenLake/your-repo
TARGET_REPO=your-test-repo
SIMILARITY_THRESHOLD=0.85
GITHUB_TOKEN=your_token_here
GITHUB_WEBHOOK_SECRET=your_secret_here
SOURCE_REPO=OpenLake/your-repo
TARGET_REPO=your-test-repo
SIMILARITY_THRESHOLD=0.85
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 2-2: [UnorderedKey] The GITHUB_TOKEN key should go before the GITHUB_WEBHOOK_SECRET key

(UnorderedKey)


[warning] 3-3: [SpaceCharacter] The line has spaces around equal sign

(SpaceCharacter)


[warning] 3-3: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)


[warning] 5-5: [SpaceCharacter] The line has spaces around equal sign

(SpaceCharacter)


[warning] 5-5: [TrailingWhitespace] Trailing whitespace detected

(TrailingWhitespace)


[warning] 5-5: [UnorderedKey] The MY_REPO_NAME key should go before the REPO_NAME key

(UnorderedKey)


[warning] 5-5: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)


[warning] 7-7: [DuplicatedKey] The GITHUB_TOKEN key is duplicated

(DuplicatedKey)


[warning] 8-8: [DuplicatedKey] The GITHUB_WEBHOOK_SECRET key is duplicated

(DuplicatedKey)


[warning] 9-9: [DuplicatedKey] The REPO_NAME key is duplicated

(DuplicatedKey)


[warning] 11-11: [DuplicatedKey] The SIMILARITY_THRESHOLD key is duplicated

(DuplicatedKey)


[warning] 11-11: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 11-11: [UnorderedKey] The SIMILARITY_THRESHOLD key should go before the TARGET_REPO key

(UnorderedKey)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.env.example around lines 1 - 11, The env example is inconsistent with the
real config contract and duplicates keys, so clean up the file to show one
canonical set of variables only. Update the example to match what app/config.py
reads by documenting GITHUB_WEBHOOK_SECRET, GITHUB_TOKEN, TARGET_REPO,
SIMILARITY_THRESHOLD, and SOURCE_REPO, and remove the conflicting
REPO_NAME/MY_REPO_NAME block so contributors see a single unambiguous template.

19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Python
__pycache__/
*.pyc

# Virtual environment
venv/
.env

# Chroma database
data/issues.json
data/chroma/chroma.sqlite3
data/chroma/defcbcc9-4578-4553-b3f4-648cbe1c763b

# IDE
.vscode/
.idea/

# OS
.DS_Store
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<<<<<<< HEAD

=======
# SmartTriage
Comment on lines +1 to 4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Remove the merge-conflict markers before merging.

The README is still in a conflicted state at both the top and bottom, which breaks the rendered docs and should block merge.

As per the provided line-range change details, both markers need to be removed.

Also applies to: 264-264

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 1 - 4, The README is still left with merge-conflict
markers, so remove the conflict artifacts and keep the intended content only.
Clean up both conflicted sections in README.md by deleting the HEAD/divider
markers and retaining the final README text, using the visible conflict blocks
near the top and bottom of the file as the locations to fix.


An intelligent GitHub bot that automates issue triage and PR reviewer assignment using vector similarity search and commit history analysis for OpenLake repositories.
Expand Down Expand Up @@ -258,3 +261,4 @@ Refer to `app/api/webhooks.py` for the full webhook routing logic.
↥ [Back to top](#table-of-contents)

If you have any questions or feedback, feel free to reach out to the maintainers or open an issue in the repository.
>>>>>>> c703023b2e677d75aef064a1828fc5d857b18b68
51 changes: 51 additions & 0 deletions app/api/webhooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from fastapi import APIRouter, Request

from app.ml.duplicate import detect_duplicate
from app.core.github import GitHubClient

router = APIRouter()

github = GitHubClient()

@router.post("/webhook")
async def github_webhook(request: Request):

event = request.headers.get("X-GitHub-Event")

print(f"GitHub Event: {event}")

try:
payload = await request.json()
except Exception:
payload = {}

Comment on lines +10 to +21

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Verify the GitHub webhook signature.

The handler accepts any POST without validating the X-Hub-Signature-256 HMAC against your webhook secret. Anyone who knows the endpoint can spoof issues/opened events and trigger comments. Compute and compare the HMAC of the raw body before processing.

Sketch
import hmac, hashlib
from app.config import WEBHOOK_SECRET

raw = await request.body()
sig = request.headers.get("X-Hub-Signature-256", "")
expected = "sha256=" + hmac.new(WEBHOOK_SECRET.encode(), raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, expected):
    raise HTTPException(status_code=401, detail="Invalid signature")
payload = json.loads(raw)
🧰 Tools
🪛 Ruff (0.15.18)

[warning] 19-19: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/api/webhooks.py` around lines 10 - 21, The github_webhook handler
currently accepts any POST request without verifying the GitHub HMAC signature.
In github_webhook, read the raw request body first, compute the expected
X-Hub-Signature-256 using the configured webhook secret, and compare it with the
incoming header using a constant-time check before parsing the payload. If the
signature is missing or invalid, return an unauthorized response and only
proceed with event processing after the signature is validated.

if event == "issues":

action = payload.get("action")

if action == "opened":
issue_text = (
payload["issue"]["title"]
+ "\n"
+ (payload["issue"]["body"] or "")
)
Comment on lines +27 to +31

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard against malformed issues payloads.

If the payload is missing issue (or title), payload["issue"]["title"] raises KeyError and returns a 500. Since the body is attacker-controllable, prefer .get() with validation and return early on bad shape.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/api/webhooks.py` around lines 27 - 31, Guard against malformed issue
payloads in the webhook handler by updating the `issue_text` construction in
`app/api/webhooks.py` to use safe accessors instead of direct indexing on
`payload["issue"]["title"]`; validate the payload shape first, return early for
missing `issue` or `title`, and keep the existing flow in the webhook parsing
logic so bad attacker-controlled input cannot raise a `KeyError` and trigger a
500.


result = detect_duplicate(issue_text)
print("Duplicate result:", result)

if result and result["duplicate"]:
github.comment_issue(
payload["issue"]["number"],

f"""
Possible duplicate issue detected.
Similar issue:
{result['issue']['url']}
Similarity:
{result['similarity']:.2f}
"""
)
Comment on lines +33 to +49

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Blocking work runs on the event loop.

detect_duplicate (model encode + Chroma query) and github.comment_issue (synchronous PyGithub HTTP calls) are blocking, but this is an async handler. They will stall the event loop and degrade concurrency under load. Offload to a thread (e.g. await run_in_threadpool(...)) or a background task.

Proposed change
-            result = detect_duplicate(issue_text)
+            from starlette.concurrency import run_in_threadpool
+            result = await run_in_threadpool(detect_duplicate, issue_text)
             print("Duplicate result:", result)

             if result and result["duplicate"]:
-                github.comment_issue(
-                    payload["issue"]["number"],
-                    ...
-                )
+                await run_in_threadpool(
+                    github.comment_issue,
+                    payload["issue"]["number"],
+                    comment_body,
+                )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/api/webhooks.py` around lines 33 - 49, The async webhook handler is
calling blocking work directly, which can stall the event loop and hurt
concurrency; in the webhook flow around detect_duplicate and
github.comment_issue, move both the duplicate detection and the PyGithub issue
comment call off the event loop using a threadpool or background task. Update
the handler in app/api/webhooks.py so the logic around
detect_duplicate(payload["issue"]["body"]) and github.comment_issue(...) is
awaited through an async-safe offload path, keeping the async request handler
non-blocking.


return {"ok": True}
10 changes: 10 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from dotenv import load_dotenv
import os

load_dotenv()

WEBHOOK_SECRET = os.getenv("GITHUB_WEBHOOK_SECRET")

@coderabbitai coderabbitai Bot Jun 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

WEBHOOK_SECRET is loaded but never used to verify webhook signatures.

The webhook handler in app/api/webhooks.py parses the request body without validating GitHub's X-Hub-Signature-256 header against this secret. As a result, the /webhook endpoint will process arbitrary forged payloads, which can trigger duplicate-detection work and post comments on issues on behalf of your token.

Compute an HMAC-SHA256 over the raw request body using WEBHOOK_SECRET and compare it (constant-time) to the X-Hub-Signature-256 header before processing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/config.py` at line 6, The webhook flow currently reads WEBHOOK_SECRET in
app/config.py but the handler in app/api/webhooks.py does not use it to
authenticate incoming requests. Update the /webhook handling logic to verify
GitHub’s X-Hub-Signature-256 against an HMAC-SHA256 computed from the raw
request body using WEBHOOK_SECRET, and reject requests when the signature is
missing or invalid before any parsing or duplicate-detection work runs. Use the
webhook handler entrypoint and request-processing logic in app/api/webhooks.py
to locate the change, and perform the comparison in constant time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@kushal281 take a look

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@Ashish-Kumar-Dash thanks for flagging this for @kushal281. This still looks like an important fix before merge: WEBHOOK_SECRET is loaded in app/config.py, but the webhook path should reject requests unless X-Hub-Signature-256 matches an HMAC-SHA256 of the raw body in constant time. Happy to re-check once that’s updated.

GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
TARGET_REPO = os.getenv("TARGET_REPO")
SIMILARITY_THRESHOLD = float(os.getenv("SIMILARITY_THRESHOLD", 0.85))
SOURCE_REPO = os.getenv("SOURCE_REPO")
42 changes: 42 additions & 0 deletions app/core/github.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from github import Github
from app.config import GITHUB_TOKEN
from app.config import TARGET_REPO

class GitHubClient:

def __init__(self):
self.client = Github(GITHUB_TOKEN)


def get_repo(self, repo_name):
return self.client.get_repo(repo_name)


def fetch_issues(self, repo_name):
repo = self.get_repo(repo_name)

issues = []

issue_iterator = repo.get_issues(state="all")

for issue in issue_iterator:

# skip pull requests
if issue.pull_request:
continue

issues.append({
"id": issue.id,
"title": issue.title,
"body": issue.body,
"url": issue.html_url,
"created_at": str(issue.created_at),
"state": issue.state
})

return issues

def comment_issue(self, issue_number, comment):
self.repo = self.get_repo(TARGET_REPO)
issue = self.repo.get_issue(number=issue_number)
issue.create_comment(comment)
42 changes: 42 additions & 0 deletions app/db/ingest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from app.core.github import GitHubClient
from app.ml.clean import clean_issue
from app.db.vector import add_issue
from app.config import SOURCE_REPO
import json
import os

def main():

github = GitHubClient()
issues = github.fetch_issues(SOURCE_REPO)

uncleaned_issues = []

for issue in issues:
cleaned = clean_issue(issue)
add_issue(
cleaned["id"],
cleaned["text"],
cleaned["vector"],
{
"state": cleaned["state"],
"url": cleaned["url"]
}
)
uncleaned_issues.append({
"id": issue['id'],
"title": issue['title'],
"body": issue['body'],
"state": issue['state'],
"url": issue['url']
})

os.makedirs("data", exist_ok=True)

with open("data/issues.json", "w", encoding="utf-8") as f:
json.dump(uncleaned_issues, f, indent=4, ensure_ascii=False)
print(f"Stored {len(issues)} issues")


if __name__ == "__main__":
main()
24 changes: 24 additions & 0 deletions app/db/vector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import chromadb
from chromadb.config import Settings

client = chromadb.PersistentClient(path="./data/chroma")


collection = client.get_or_create_collection(name="github_issues")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What is the default distance metric for a ChromaDB get_or_create_collection, and how do you configure cosine distance in chromadb 0.4.6?

💡 Result:

The default distance metric for a ChromaDB collection is l2 (Squared Euclidean distance) [1][2]. In ChromaDB version 0.4.6, the configuration dictionary parameter (which became standard in later versions like 1.0) was not yet the primary interface for index settings [2]. Instead, you configure the distance metric by passing a metadata dictionary to the get_or_create_collection method using the hnsw:space key [3][4]. To configure cosine distance in chromadb 0.4.6, use the following syntax: collection = client.get_or_create_collection( name="your_collection_name", metadata={"hnsw:space": "cosine"}) Important notes: 1. Distance vs. Similarity: ChromaDB's cosine setting returns cosine distance (1 - cosine similarity), meaning values closer to 0 indicate higher similarity [1][3]. 2. Immutability: The distance metric cannot be changed once a collection has been created [1][2]. If you need a different metric, you must delete the collection and recreate it, or clone it into a new collection with the desired setting [1]. 3. Legacy Metadata: While newer versions of Chroma now prefer a configuration argument for these settings, version 0.4.6 relies on the metadata parameter to pass HNSW-specific configurations like hnsw:space [2][3][4].

Citations:


Set an explicit cosine distance metric for the collection.

The default distance metric for get_or_create_collection in ChromaDB 0.4.6 is L2. Since app/ml/duplicate.py calculates similarity = max(0, 1 - distance), it expects the distance values to be bounded (specifically within [0, 2] for cosine distance). Using unbounded L2 distances with this formula produces incorrect similarity scores. You must configure the collection to use the cosine space during creation.

Proposed change
-collection = client.get_or_create_collection(name="github_issues")
+collection = client.get_or_create_collection(
+    name="github_issues",
+    metadata={"hnsw:space": "cosine"},
+)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
collection = client.get_or_create_collection(name="github_issues")
collection = client.get_or_create_collection(
name="github_issues",
metadata={"hnsw:space": "cosine"},
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/db/vector.py` at line 7, The collection created in
client.get_or_create_collection for github_issues is using the default L2
distance, which breaks the similarity math used by app.ml.duplicate's similarity
calculation. Update the collection creation in app.db.vector so github_issues is
created with an explicit cosine distance metric/space, keeping the returned
distances compatible with max(0, 1 - distance).



def add_issue(issue_id, text, vector, metadata):
collection.upsert(
ids=[str(issue_id)],
documents=[text],
embeddings=[vector],
metadatas=[metadata]
)


def search_similar_issue(embedding, limit=1):
results = collection.query(
query_embeddings=[embedding],
n_results=limit
)
return results
10 changes: 10 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from fastapi import FastAPI
from app.api.webhooks import router

app = FastAPI(title="SmartTriage")

app.include_router(router)

@app.get("/health")
def health():
return {"status": "ok"}
22 changes: 22 additions & 0 deletions app/ml/clean.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from app.ml.embedder import Embedder

embedder = Embedder()

def clean_issue(issue):
text = ""

if issue["title"]:
text += issue["title"]

if issue["body"]:
text += "\n" + issue["body"]

vector = embedder.generate_embedding(text)

return {
"id": issue["id"],
"text": text.strip(),
"url": issue["url"],
"state": issue["state"],
"vector": vector
}
30 changes: 30 additions & 0 deletions app/ml/duplicate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from app.ml.embedder import Embedder
from app.db.vector import search_similar_issue
from app.config import SIMILARITY_THRESHOLD

embedder = Embedder()

def detect_duplicate(issue_text):

embedding = embedder.generate_embedding(issue_text)

result = search_similar_issue(embedding)


if not result["distances"][0]:
return None

distance = result["distances"][0][0]
similarity = max(0, 1 - distance)

if similarity >= SIMILARITY_THRESHOLD:
return {
"duplicate": True,
"similarity": similarity,
"issue": result["metadatas"][0][0]
}

return {
"duplicate": False,
"similarity": similarity
}
9 changes: 9 additions & 0 deletions app/ml/embedder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from sentence_transformers import SentenceTransformer

class Embedder:
def __init__(self):
self.model = SentenceTransformer("all-MiniLM-L6-v2")

def generate_embedding(self, text):
embedding = self.model.encode(text)
return embedding.tolist()
19 changes: 19 additions & 0 deletions app/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from app.ml.embedder import Embedder
from app.db.vector import search_similar


embedder = Embedder()


text = "Cannot login into application"


embedding = embedder.generate_embedding(text)


result = search_similar(
embedding
)
Comment on lines +2 to +16

@coderabbitai coderabbitai Bot Jun 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Import name mismatch — search_similar does not exist.

app/db/vector.py defines search_similar_issue, not search_similar. This import raises ImportError and the call on Line 14 would also fail.

Proposed fix
-from app.db.vector import search_similar
+from app.db.vector import search_similar_issue
@@
-result = search_similar(
-    embedding
-)
+result = search_similar_issue(
+    embedding
+)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from app.db.vector import search_similar
embedder = Embedder()
text = "Cannot login into application"
embedding = embedder.generate_embedding(text)
result = search_similar(
embedding
)
from app.db.vector import search_similar_issue
embedder = Embedder()
text = "Cannot login into application"
embedding = embedder.generate_embedding(text)
result = search_similar_issue(
embedding
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/test.py` around lines 2 - 16, The test is importing and calling the wrong
vector search helper: `app.db.vector` exposes `search_similar_issue`, not
`search_similar`. Update the import in `app/test.py` to use the सही function
name, and adjust the call site to invoke `search_similar_issue` with the
embedding so the test matches the actual API.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@Ashish-Kumar-Dash thanks for tagging them. The review note still stands as written: app/test.py currently imports/calls search_similar, while app/db/vector.py exposes search_similar_issue.

The minimal fix is:

from app.db.vector import search_similar_issue

result = search_similar_issue(embedding)



print(result)
Binary file added requirements.txt
Binary file not shown.