Skip to content
Merged
2 changes: 2 additions & 0 deletions Backend/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,11 @@ def invalid_token_callback(error_string):
from app.auth.routes import auth as auth_blueprint
from app.profile.routes import profile as profile_blueprint
from app.main.routes import main as main_blueprint
from app.claude.routes import claude as claude_blueprint

app.register_blueprint(auth_blueprint)
app.register_blueprint(profile_blueprint)
app.register_blueprint(main_blueprint)
app.register_blueprint(claude_blueprint)

return app
Empty file added Backend/app/claude/__init__.py
Empty file.
122 changes: 122 additions & 0 deletions Backend/app/claude/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from anthropic import Anthropic, APIError
import httpx
import os
import logging
import sys

# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

claude = Blueprint("claude", __name__)

# Get API key
logger.info("Current directory: %s", os.getcwd())
logger.info("Python path: %s", sys.path)
logger.info("Environment variables: %s",
{k: v for k, v in os.environ.items() if 'KEY' in k or 'SECRET' in k or 'PASSWORD' in k})
api_key = os.environ.get('ANTHROPIC_API_KEY')
logger.info(f"API Key present: {bool(api_key)}")

try:
client = httpx.Client()
anthropic = Anthropic(
api_key=api_key,
http_client=client
)
logger.info("Anthropic client initialized successfully")
logger.info(f"Anthropic client: {anthropic}")
logger.info("Api key: " + api_key)
except Exception as e:
logger.error(f"Failed to initialize Anthropic client: {str(e)}")
anthropic = None

@claude.route('/claude/generate', methods=['POST'])
def generate_content():
"""
Generate proposal content using Claude AI.
"""
# Log request received
logger.info("Received generation request")

# Check API key first
if not api_key:
logger.error("No API key found")
return jsonify({
'error': 'API key not configured',
'api_status': 'missing'
}), 500

# Check client initialization
if not anthropic:
logger.error("Anthropic client not initialized")
return jsonify({
'error': 'Anthropic client not initialized',
'api_status': 'client_error'
}), 500

try:
# Get and validate request data
data = request.get_json()
if not data:
logger.error("No JSON data in request")
return jsonify({'error': 'No JSON data provided'}), 400

if 'prompt' not in data or 'section' not in data:
logger.error(f"Missing required fields. Received fields: {data.keys()}")
return jsonify({'error': 'Missing required fields: prompt and/or section'}), 400

logger.info(f"Generating content for section: {data['section']}")

try:
# Generate content using Claude
message = anthropic.messages.create(
model="claude-3-haiku-20240307",
max_tokens=1500,
messages=[{
"role": "user",
"content": data['prompt']
}],
temperature=0.7,
)

if not message.content:
logger.error("No content generated")
return jsonify({
'error': 'Content generation failed',
'api_status': 'generation_error'
}), 500

generated_content = message.content[0].text
logger.info("Content generated successfully")

return jsonify({
'content': generated_content,
'status': 'success'
}), 200

except APIError as ae:
logger.error(f"Anthropic API error: {str(ae)}")
return jsonify({
'error': 'Anthropic API error',
'details': str(ae),
'api_status': 'api_error'
}), 500

except Exception as e:
logger.error(f"Generation error: {str(e)}")
return jsonify({
'error': 'Content generation failed',
'details': str(e),
'api_status': 'generation_error'
}), 500

except Exception as e:
logger.error(f"Request processing error: {str(e)}")
return jsonify({
'error': 'Request processing failed',
'details': str(e),
'api_status': 'request_error'
}), 500
24 changes: 13 additions & 11 deletions Backend/app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ class AppConfig:
database_url = os.getenv("DATABASE_URL")
if database_url and database_url.startswith("postgres://"):
database_url = database_url.replace("postgres://", "postgresql://")

# Determine environment and database connection
IS_MIGRATION = os.getenv('IS_MIGRATION') == 'true'
IS_CLOUD_RUN = os.getenv('K_SERVICE') is not None
USE_CLOUD_SQL_PROXY = os.getenv('USE_CLOUD_SQL_PROXY') == 'true'

# Database URI Configuration
if IS_MIGRATION or USE_CLOUD_SQL_PROXY:
# Use Cloud SQL Proxy connection for migrations or when explicitly requested
Expand All @@ -29,13 +29,13 @@ class AppConfig:
else:
# Local development fallback
SQLALCHEMY_DATABASE_URI = database_url or "sqlite:///db.sqlite"

# Determine database type to set appropriate configuration
is_sqlite = SQLALCHEMY_DATABASE_URI.startswith('sqlite')

# Base SQLAlchemy configuration
SQLALCHEMY_TRACK_MODIFICATIONS = False

# Configure engine options based on database type
if is_sqlite:
SQLALCHEMY_ENGINE_OPTIONS = {
Expand All @@ -55,25 +55,25 @@ class AppConfig:
'connect_timeout': 30
} if not is_sqlite else {}
}

# Session configuration
SESSION_TYPE = "filesystem"
SESSION_COOKIE_SAMESITE = "None"
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_DOMAIN = '.onrender.com' if os.getenv('FLASK_ENV') == 'production' else None

# Mail configuration
MAIL_USERNAME = os.getenv("MAIL_USERNAME")
MAIL_PASSWORD = os.getenv("MAIL_PASSWORD")
MAIL_SERVER = "smtp.googlemail.com"
MAIL_PORT = 587
MAIL_USE_TLS = True

# File upload configuration
UPLOAD_FOLDER = os.path.abspath("uploads")
ENV = os.getenv("FLASK_ENV", "production")

# JWT settings
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY")
JWT_ACCESS_TOKEN_EXPIRES = timedelta(days=1)
Expand All @@ -85,12 +85,14 @@ class AppConfig:
# Google Cloud configuration
GOOGLE_CLOUD_PROJECT = os.getenv("GOOGLE_CLOUD_PROJECT")
GOOGLE_APPLICATION_CREDENTIALS = os.getenv("GOOGLE_APPLICATION_CREDENTIALS")
GCS_BUCKET_NAME = os.environ.get("GCS_BUCKET_NAME")

GCS_BUCKET_NAME = os.environ.get('GCS_BUCKET_NAME')
# Anthropic API key
ANTHROPIC_API_KEY = os.getenv('ANTHROPIC_API_KEY')

class TestConfig(AppConfig):
SQLALCHEMY_DATABASE_URI = "sqlite://"
TESTING = True
SQLALCHEMY_ENGINE_OPTIONS = {
'pool_pre_ping': True
} # Simplified options for testing
} # Simplified options for testing
1 change: 1 addition & 0 deletions Backend/requirements.dev.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Core dependencies
anthropic>=0.10.0
bcrypt>=4.0.1
Flask>=2.2.3
Flask-Bcrypt>=1.0.1
Expand Down
1 change: 1 addition & 0 deletions Backend/requirements.prod.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Core dependencies
anthropic>=0.10.0
bcrypt==4.0.1
Flask==2.2.3
Flask-Bcrypt==1.0.1
Expand Down
11 changes: 6 additions & 5 deletions Frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import VolunteerPage from './pages/VolunteerPage';
import SelectUserTypePage from './pages/SelectUserTypePage';
import EstablishmentGuide from './pages/EstablishmentGuide';
import EditProfile from './pages/EditProfilePage';
import ProfileImages from './components/OrgProfileFormComponents/ProfileImages';
import ProfileImages from "./components/OrgProfileFormComponents/ProfileImages";
import ProposalBuilderPage from './pages/ProposalBuilderPage';


function App() {
Expand All @@ -37,19 +38,19 @@ function App() {
<Route path="/home" element={<DisplayPage />} />
<Route path="/find-gos" element={<DisplayPage />} />
<Route path="/" element={<Navigate to="/find-gos" />} />

<Route path="/onboarding" element={<OnboardingForm />} />
<Route path="/org_profile_form" element={<OrgProfileForm />} />
<Route path="/org_profile" element={<OrgProfile />} />
<Route path="/upload-images" element={<ProfileImages />} />
<Route path="/edit_profile" element={<EditProfile />} />

<Route path="/establishment-guide" element={<EstablishmentGuide />} />
<Route path="/proposal-builder" element={<ProposalBuilderPage />} />
</Routes>
</TranslationProvider>
</TranslationProvider>
</ApiProvider>
</AuthProvider>
</BrowserRouter>
</AuthProvider>
</BrowserRouter>
</Container>
);
}
Expand Down
1 change: 1 addition & 0 deletions Frontend/src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const navigation = [
{ name: "Home", href: "/" },
{ name: "Find GOs", href: "/find-gos" },
{ name: "Establishment Guide", href: "/establishment-guide" },
{ name: "Proposal Builder", href: "/proposal-builder" },
{ name: "Volunteer", href: "/volunteer" },
{ name: "About", href: "/about" },
];
Expand Down
Loading