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
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,15 @@ chmod +x ./bash.sh

### 3. Manual approach

### 3.1. Backend Setup
### 3.1 Environment Configuration

Before running the backend or frontend, configure the environment variables:

1. In the `backend` folder, copy `.env.example` to `.env`.
- **Important**: Consider adding a `GITHUB_TOKEN` to your `backend/.env` file to prevent GitHub API rate limits.
2. In the `frontend` folder, copy `.env.example` to `.env`.

### 3.2. Backend Setup

```bash
cd backend
Expand Down
7 changes: 7 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FLASK_HOST=127.0.0.1
FLASK_PORT=5000
OSDG_API_URL=http://20.73.166.85/label_text
OSDG_TOKEN=your_osdg_token_here
AURORA_API_URL=https://aurora-sdg.labs.vu.nl/classifier/classify/elsevier-sdg-multi
GITHUB_API_URL=https://api.github.com
GITHUB_TOKEN=your_github_token_here
65 changes: 58 additions & 7 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,20 @@
from embedding_description import main as classify_description
from embedding_url import main as classify_url
from aurora_api import main as aurora_classify
import re
from dotenv import load_dotenv

load_dotenv()

app = Flask(__name__)
CORS(app)

def is_valid_github_url(url):
if not url:
return False
pattern = r'^https?:\/\/(www\.)?github\.com\/[\w.-]+\/[\w.-]+\/?$'
return re.match(pattern, url) is not None



@app.route('/api/hello', methods=['GET'])
Expand All @@ -30,6 +39,9 @@ def classify_aurora():

if not projectDescription:
return jsonify({'error': 'Project description is required'}), 400

if not is_valid_github_url(projectUrl):
return jsonify({'error': 'A valid GitHub repository URL is required'}), 400



Expand All @@ -41,12 +53,19 @@ def classify_aurora():
project_name=projectName,
project_url=projectUrl
)

if "error" in aurora_result:
print(f"Aurora API returned an error: {aurora_result['error']}")
return jsonify({
"error": aurora_result["error"],
"message": aurora_result.get("message", "Aurora API classification failed")
}), 502

print("Aurora API model completed successfully")
except Exception as e:
print(f"Aurora API model failed: {str(e)}")
return jsonify({
"error": str(e),
"error": "Internal processing error occurred.",
"message": "Aurora API classification failed"
}), 500

Expand Down Expand Up @@ -78,6 +97,9 @@ def classify_st_description():

if not projectDescription:
return jsonify({'error': 'Project description is required'}), 400

if not is_valid_github_url(projectUrl):
return jsonify({'error': 'A valid GitHub repository URL is required'}), 400


# 3. Sentence Transformer Description Model (text-based)
Expand All @@ -93,7 +115,7 @@ def classify_st_description():
except Exception as e:
print(f"ST Description model failed: {str(e)}")
st_desc_result = {
"error": str(e),
"error": "Internal processing error occurred.",
"message": "Sentence Transformer Description model classification failed"
}
return jsonify(st_desc_result), 500
Expand Down Expand Up @@ -121,6 +143,9 @@ def classify_st_url():

if not projectDescription:
return jsonify({'error': 'Project description is required'}), 400

if not is_valid_github_url(projectUrl):
return jsonify({'error': 'A valid GitHub repository URL is required'}), 400



Expand All @@ -134,16 +159,26 @@ def classify_st_url():
except ValueError as ve:
print(f"ST URL model invalid URL: {str(ve)}")
return jsonify({'error': str(ve)}), 400
except requests.exceptions.Timeout:
return jsonify({
"error": "The request to GitHub timed out. Please try again later.",
"message": "Network timeout error"
}), 504
except requests.exceptions.ConnectionError:
return jsonify({
"error": "Failed to connect to GitHub. Please check your network connection.",
"message": "Network connection error"
}), 502
except requests.exceptions.HTTPError as he:
print(f"ST URL model HTTP Error: {str(he)}")
return jsonify({
"error": f"Failed to fetch repository data. Please ensure the repository is public and exists. ({str(he)})",
"error": "Failed to fetch repository data. Please ensure the repository is public and exists.",
"message": "Sentence Transformer URL model classification failed"
}), 400
except Exception as e:
print(f"ST URL model failed: {str(e)}")
return jsonify({
"error": str(e),
"error": "An internal error occurred while processing the repository URL.",
"message": "Sentence Transformer URL model classification failed"
}), 500
else:
Expand Down Expand Up @@ -171,11 +206,15 @@ def osdg_external_api():

if not projectDescription:
return jsonify({'error': 'Project description is required'}), 400

if not is_valid_github_url(projectUrl):
return jsonify({'error': 'A valid GitHub repository URL is required'}), 400

# Call the external OSDG API
osdg_url = os.environ.get("OSDG_API_URL", "http://20.73.166.85/label_text")
try:
osdg_response = requests.post(
"http://20.73.166.85/label_text",
osdg_url,
json={
"text": projectDescription
},
Expand All @@ -186,10 +225,20 @@ def osdg_external_api():
)
osdg_response.raise_for_status() # Raise an error for bad status codes
osdg_result = osdg_response.json()
except requests.exceptions.Timeout:
return jsonify({
"error": "The request to the OSDG API timed out.",
"message": "Network timeout error"
}), 504
except requests.exceptions.ConnectionError:
return jsonify({
"error": "Failed to connect to the OSDG API.",
"message": "Network connection error"
}), 502
except requests.exceptions.RequestException as e:
print(f"OSDG API request failed: {str(e)}")
return jsonify({
"error": f"Failed to connect to OSDG API: {str(e)}",
"error": "Failed to communicate with OSDG API.",
"message": "OSDG API classification failed"
}), 500

Expand Down Expand Up @@ -236,4 +285,6 @@ def osdg_external_api():
# }), 200

if __name__ == '__main__':
app.run(debug=True)
host = os.environ.get("FLASK_HOST", "127.0.0.1")
port = int(os.environ.get("FLASK_PORT", 5000))
app.run(host=host, port=port, debug=True)
24 changes: 20 additions & 4 deletions backend/aurora_api.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import requests
import json
from sdg_constants import SDG_LABELS_DICT as SDG_LABELS
Expand All @@ -16,7 +17,7 @@ def main(text: str, project_name: str = None, project_url: str = None):
Dictionary with predictions in standardized format
"""
try:
url = "https://aurora-sdg.labs.vu.nl/classifier/classify/elsevier-sdg-multi"
url = os.environ.get("AURORA_API_URL", "https://aurora-sdg.labs.vu.nl/classifier/classify/elsevier-sdg-multi")
payload = json.dumps({"text": text})
headers = {'Content-Type': 'application/json'}
response = requests.request("POST", url, headers=headers, data=payload)
Expand Down Expand Up @@ -90,20 +91,35 @@ def main(text: str, project_name: str = None, project_url: str = None):

return formatted_result

except requests.exceptions.Timeout:
return {
"project_name": project_name or "Unknown",
"project_url": project_url or "",
"sdg_predictions": {},
"error": "The request to the Aurora API timed out.",
"message": "Network timeout error"
}
except requests.exceptions.ConnectionError:
return {
"project_name": project_name or "Unknown",
"project_url": project_url or "",
"sdg_predictions": {},
"error": "Failed to connect to the Aurora API.",
"message": "Network connection error"
}
except requests.exceptions.RequestException as e:

return {
"project_name": project_name or "Unknown",
"project_url": project_url or "",
"sdg_predictions": {},
"error": str(e),
"error": "Failed to communicate with Aurora API.",
"message": "Aurora API request failed"
}
except Exception as e:
return {
"project_name": project_name or "Unknown",
"project_url": project_url or "",
"sdg_predictions": {},
"error": f"{type(e).__name__}: {str(e)}",
"error": "An internal error occurred during classification.",
"message": "Aurora API processing failed"
}
2 changes: 1 addition & 1 deletion backend/embedding_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from sdg_constants import SDG_LABELS, SDG_NAMES, SDG_DESCS

# --- GitHub fetch utilities ---
GITHUB_API = "https://api.github.com"
GITHUB_API = os.environ.get("GITHUB_API_URL", "https://api.github.com")

def parse_repo(url: str) -> Tuple[str, str]:
"""
Expand Down
3 changes: 2 additions & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ numpy
accelerate
flask
flask-cors
Flask-UUID
Flask-UUID
python-dotenv
40 changes: 21 additions & 19 deletions frontend/components/mainScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,31 @@ const MainScreen: React.FC<{
const handleFormSubmit = async (e: React.FormEvent) => {
e.preventDefault();

if (
!projectName ||
!projectUrl ||
!projectDescription
// !problemStatement ||
// !longTermGoal ||
// !solutionApproach ||
// !targetAudience
) {
const trimmedName = projectName.trim();
const trimmedUrl = projectUrl.trim();
const trimmedDesc = projectDescription.trim();

if (!trimmedName || !trimmedUrl || !trimmedDesc) {
setUploadMsg("Please fill in all required fields before submitting.");
return;
}

if (projectUrl.includes("github.com") === false) {
setUploadMsg("Please enter a valid GitHub repository URL.");
// GitHub URL validation regex
const githubUrlRegex = /^https?:\/\/(www\.)?github\.com\/[\w.-]+\/[\w.-]+\/?$/;
if (!githubUrlRegex.test(trimmedUrl)) {
setUploadMsg("Please enter a valid GitHub repository URL (e.g., https://github.com/username/repository).");
return;
}

const finalizedData = {
projectName: projectName,
projectUrl: projectUrl,
projectDescription: projectDescription,
projectName: trimmedName,
projectUrl: trimmedUrl,
projectDescription: trimmedDesc,
};

localStorage.setItem("projectDescription", projectDescription);
localStorage.setItem("projectName", projectName);
localStorage.setItem("projectUrl", projectUrl);
localStorage.setItem("projectDescription", trimmedDesc);
localStorage.setItem("projectName", trimmedName);
localStorage.setItem("projectUrl", trimmedUrl);

try {
setIsUploading(true);
Expand Down Expand Up @@ -89,9 +87,13 @@ const MainScreen: React.FC<{

// console.log("API Response:", response.data);
setResults(response as ResultsData);
} catch (error) {
} catch (error: any) {
console.error("Error:", error);
setUploadMsg("Text Analyzing Failed. Please try again.");
const backendError = error.response?.data?.message || error.response?.data?.error;
const fallbackError = error.message === "Network Error"
? "Network error: Unable to reach the server. Please try again later."
: "Text Analyzing Failed. Please try again.";
setUploadMsg(backendError || fallbackError);
} finally {
setIsUploading(false);
}
Expand Down
Loading