Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -15,7 +15,7 @@ logger.info("=" * 80)
|
|
| 15 |
logger.info("π Job Application Agent - Startup")
|
| 16 |
logger.info("=" * 80)
|
| 17 |
|
| 18 |
-
# Add src to Python path
|
| 19 |
current_dir = os.path.dirname(os.path.abspath(__file__))
|
| 20 |
src_path = os.path.join(current_dir, 'src')
|
| 21 |
if src_path not in sys.path:
|
|
@@ -28,7 +28,8 @@ logger.info(f"β Python path updated")
|
|
| 28 |
# Import Gradio
|
| 29 |
try:
|
| 30 |
import gradio as gr
|
| 31 |
-
|
|
|
|
| 32 |
except ImportError as e:
|
| 33 |
logger.error(f"β Failed to import Gradio: {e}")
|
| 34 |
logger.error("Install with: pip install gradio")
|
|
@@ -43,10 +44,9 @@ except ImportError as e:
|
|
| 43 |
logger.error("Install with: pip install torch")
|
| 44 |
sys.exit(1)
|
| 45 |
|
| 46 |
-
# Import application components
|
| 47 |
logger.info("\nπ¦ Attempting to import application modules...")
|
| 48 |
|
| 49 |
-
# Create fallback/mock classes if imports fail
|
| 50 |
mayini_model = None
|
| 51 |
vocab = None
|
| 52 |
customizer = None
|
|
@@ -63,7 +63,6 @@ except ImportError as e:
|
|
| 63 |
logger.warning(f" β οΈ Could not import MAYINI: {e}")
|
| 64 |
logger.warning(" Creating mock MAYINI classes...")
|
| 65 |
|
| 66 |
-
# Create mock classes
|
| 67 |
class MAYINIVocabulary:
|
| 68 |
def __init__(self, vocab_size=5000):
|
| 69 |
self.vocab_size = vocab_size
|
|
@@ -120,8 +119,6 @@ except ImportError as e:
|
|
| 120 |
return self.jobs
|
| 121 |
def search_jobs(self, keywords=None, location=None, limit=10):
|
| 122 |
return self.jobs[:limit]
|
| 123 |
-
def filter_by_experience(self, jobs, min_years=0, max_years=10):
|
| 124 |
-
return [j for j in jobs if min_years <= j.get('experience_required', 0) <= max_years]
|
| 125 |
|
| 126 |
logger.info(" β Mock Scraper class created")
|
| 127 |
|
|
@@ -201,7 +198,7 @@ except ImportError as e:
|
|
| 201 |
logger.info(" β Mock Agent class created")
|
| 202 |
|
| 203 |
logger.info("\n" + "=" * 80)
|
| 204 |
-
logger.info("β
All components loaded
|
| 205 |
logger.info("=" * 80)
|
| 206 |
|
| 207 |
# ============================================================================
|
|
@@ -213,55 +210,23 @@ logger.info("\nπ§ Initializing components...")
|
|
| 213 |
try:
|
| 214 |
vocab = MAYINIVocabulary(vocab_size=5000)
|
| 215 |
logger.info("β MAYINI Vocabulary initialized")
|
| 216 |
-
|
| 217 |
-
logger.error(f"Error initializing vocabulary: {e}")
|
| 218 |
-
vocab = MAYINIVocabulary()
|
| 219 |
-
|
| 220 |
-
try:
|
| 221 |
-
mayini_model = MAYINIModel(
|
| 222 |
-
vocab_size=5000,
|
| 223 |
-
hidden_dim=256,
|
| 224 |
-
num_heads=8,
|
| 225 |
-
num_layers=4
|
| 226 |
-
)
|
| 227 |
mayini_model.eval()
|
| 228 |
logger.info("β MAYINI Model initialized")
|
| 229 |
-
except Exception as e:
|
| 230 |
-
logger.error(f"Error initializing model: {e}")
|
| 231 |
-
mayini_model = MAYINIModel()
|
| 232 |
-
|
| 233 |
-
try:
|
| 234 |
scraper = JobScraper()
|
| 235 |
logger.info("β Job Scraper initialized")
|
| 236 |
-
except Exception as e:
|
| 237 |
-
logger.error(f"Error initializing scraper: {e}")
|
| 238 |
-
scraper = JobScraper()
|
| 239 |
-
|
| 240 |
-
try:
|
| 241 |
customizer = ResumeCustomizer(mayini_model, vocab)
|
| 242 |
logger.info("β Resume Customizer initialized")
|
| 243 |
-
except Exception as e:
|
| 244 |
-
logger.error(f"Error initializing customizer: {e}")
|
| 245 |
-
customizer = ResumeCustomizer(mayini_model, vocab)
|
| 246 |
-
|
| 247 |
-
try:
|
| 248 |
classifier = JobRelevanceClassifier()
|
| 249 |
-
if hasattr(classifier, 'mayini_model'):
|
| 250 |
-
classifier.mayini_model = mayini_model
|
| 251 |
logger.info("β Job Classifier initialized")
|
| 252 |
-
except Exception as e:
|
| 253 |
-
logger.error(f"Error initializing classifier: {e}")
|
| 254 |
-
classifier = JobRelevanceClassifier()
|
| 255 |
-
|
| 256 |
-
try:
|
| 257 |
agent = JobApplicationAgent(scraper, customizer, classifier)
|
| 258 |
logger.info("β Application Agent initialized")
|
| 259 |
except Exception as e:
|
| 260 |
-
logger.error(f"Error
|
| 261 |
-
|
| 262 |
|
| 263 |
logger.info("\n" + "=" * 80)
|
| 264 |
-
logger.info("β
INITIALIZATION COMPLETE -
|
| 265 |
logger.info("=" * 80 + "\n")
|
| 266 |
|
| 267 |
# ============================================================================
|
|
@@ -397,39 +362,82 @@ with gr.Blocks(title="Job Application Agent", theme=gr.themes.Soft()) as demo:
|
|
| 397 |
gr.Markdown("Find jobs matching your skills using AI-powered matching.")
|
| 398 |
with gr.Row():
|
| 399 |
with gr.Column():
|
| 400 |
-
search_keywords = gr.Textbox(
|
| 401 |
-
|
| 402 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 403 |
search_btn = gr.Button("π Search", variant="primary")
|
| 404 |
with gr.Column():
|
| 405 |
search_output = gr.Markdown(value="### Results will appear here...")
|
| 406 |
|
| 407 |
-
search_btn.click(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
|
| 409 |
with gr.Tab("π Customize Resume"):
|
| 410 |
gr.Markdown("Tailor your resume for specific job opportunities.")
|
| 411 |
with gr.Row():
|
| 412 |
with gr.Column():
|
| 413 |
-
customize_title = gr.Textbox(
|
| 414 |
-
|
| 415 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
customize_btn = gr.Button("β¨ Customize", variant="primary")
|
| 417 |
with gr.Column():
|
| 418 |
customize_output = gr.Markdown(value="### Customized resume will appear here...")
|
| 419 |
|
| 420 |
-
customize_btn.click(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 421 |
|
| 422 |
with gr.Tab("π― Classify Job"):
|
| 423 |
gr.Markdown("Check job relevance to your skills.")
|
| 424 |
with gr.Row():
|
| 425 |
with gr.Column():
|
| 426 |
-
classify_title = gr.Textbox(
|
| 427 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 428 |
classify_btn = gr.Button("π― Classify", variant="primary")
|
| 429 |
with gr.Column():
|
| 430 |
classify_output = gr.Markdown(value="### Results will appear here...")
|
| 431 |
|
| 432 |
-
classify_btn.click(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
|
| 434 |
with gr.Tab("βΉοΈ About"):
|
| 435 |
gr.Markdown("""
|
|
@@ -455,7 +463,7 @@ with gr.Blocks(title="Job Application Agent", theme=gr.themes.Soft()) as demo:
|
|
| 455 |
logger.info("β Gradio interface built successfully\n")
|
| 456 |
|
| 457 |
# ============================================================================
|
| 458 |
-
# LAUNCH
|
| 459 |
# ============================================================================
|
| 460 |
|
| 461 |
if __name__ == "__main__":
|
|
@@ -463,7 +471,9 @@ if __name__ == "__main__":
|
|
| 463 |
logger.info("Access at: http://0.0.0.0:7860\n")
|
| 464 |
|
| 465 |
try:
|
| 466 |
-
|
|
|
|
|
|
|
| 467 |
server_name="0.0.0.0",
|
| 468 |
server_port=7860,
|
| 469 |
show_error=True,
|
|
|
|
| 15 |
logger.info("π Job Application Agent - Startup")
|
| 16 |
logger.info("=" * 80)
|
| 17 |
|
| 18 |
+
# Add src to Python path
|
| 19 |
current_dir = os.path.dirname(os.path.abspath(__file__))
|
| 20 |
src_path = os.path.join(current_dir, 'src')
|
| 21 |
if src_path not in sys.path:
|
|
|
|
| 28 |
# Import Gradio
|
| 29 |
try:
|
| 30 |
import gradio as gr
|
| 31 |
+
gradio_version = gr.__version__
|
| 32 |
+
logger.info(f"β Gradio imported successfully (version: {gradio_version})")
|
| 33 |
except ImportError as e:
|
| 34 |
logger.error(f"β Failed to import Gradio: {e}")
|
| 35 |
logger.error("Install with: pip install gradio")
|
|
|
|
| 44 |
logger.error("Install with: pip install torch")
|
| 45 |
sys.exit(1)
|
| 46 |
|
| 47 |
+
# Import application components
|
| 48 |
logger.info("\nπ¦ Attempting to import application modules...")
|
| 49 |
|
|
|
|
| 50 |
mayini_model = None
|
| 51 |
vocab = None
|
| 52 |
customizer = None
|
|
|
|
| 63 |
logger.warning(f" β οΈ Could not import MAYINI: {e}")
|
| 64 |
logger.warning(" Creating mock MAYINI classes...")
|
| 65 |
|
|
|
|
| 66 |
class MAYINIVocabulary:
|
| 67 |
def __init__(self, vocab_size=5000):
|
| 68 |
self.vocab_size = vocab_size
|
|
|
|
| 119 |
return self.jobs
|
| 120 |
def search_jobs(self, keywords=None, location=None, limit=10):
|
| 121 |
return self.jobs[:limit]
|
|
|
|
|
|
|
| 122 |
|
| 123 |
logger.info(" β Mock Scraper class created")
|
| 124 |
|
|
|
|
| 198 |
logger.info(" β Mock Agent class created")
|
| 199 |
|
| 200 |
logger.info("\n" + "=" * 80)
|
| 201 |
+
logger.info("β
All components loaded")
|
| 202 |
logger.info("=" * 80)
|
| 203 |
|
| 204 |
# ============================================================================
|
|
|
|
| 210 |
try:
|
| 211 |
vocab = MAYINIVocabulary(vocab_size=5000)
|
| 212 |
logger.info("β MAYINI Vocabulary initialized")
|
| 213 |
+
mayini_model = MAYINIModel(vocab_size=5000, hidden_dim=256, num_heads=8, num_layers=4)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
mayini_model.eval()
|
| 215 |
logger.info("β MAYINI Model initialized")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
scraper = JobScraper()
|
| 217 |
logger.info("β Job Scraper initialized")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
customizer = ResumeCustomizer(mayini_model, vocab)
|
| 219 |
logger.info("β Resume Customizer initialized")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
classifier = JobRelevanceClassifier()
|
|
|
|
|
|
|
| 221 |
logger.info("β Job Classifier initialized")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
agent = JobApplicationAgent(scraper, customizer, classifier)
|
| 223 |
logger.info("β Application Agent initialized")
|
| 224 |
except Exception as e:
|
| 225 |
+
logger.error(f"Error during initialization: {e}")
|
| 226 |
+
logger.error(traceback.format_exc())
|
| 227 |
|
| 228 |
logger.info("\n" + "=" * 80)
|
| 229 |
+
logger.info("β
INITIALIZATION COMPLETE - Ready to serve!")
|
| 230 |
logger.info("=" * 80 + "\n")
|
| 231 |
|
| 232 |
# ============================================================================
|
|
|
|
| 362 |
gr.Markdown("Find jobs matching your skills using AI-powered matching.")
|
| 363 |
with gr.Row():
|
| 364 |
with gr.Column():
|
| 365 |
+
search_keywords = gr.Textbox(
|
| 366 |
+
label="Keywords",
|
| 367 |
+
placeholder="python docker aws",
|
| 368 |
+
value="python"
|
| 369 |
+
)
|
| 370 |
+
search_location = gr.Textbox(
|
| 371 |
+
label="Location",
|
| 372 |
+
placeholder="Remote",
|
| 373 |
+
value="Remote"
|
| 374 |
+
)
|
| 375 |
+
search_num = gr.Slider(
|
| 376 |
+
minimum=1,
|
| 377 |
+
maximum=20,
|
| 378 |
+
value=5,
|
| 379 |
+
step=1,
|
| 380 |
+
label="Number of Jobs"
|
| 381 |
+
)
|
| 382 |
search_btn = gr.Button("π Search", variant="primary")
|
| 383 |
with gr.Column():
|
| 384 |
search_output = gr.Markdown(value="### Results will appear here...")
|
| 385 |
|
| 386 |
+
search_btn.click(
|
| 387 |
+
fn=search_jobs_interface,
|
| 388 |
+
inputs=[search_keywords, search_location, search_num],
|
| 389 |
+
outputs=search_output
|
| 390 |
+
)
|
| 391 |
|
| 392 |
with gr.Tab("π Customize Resume"):
|
| 393 |
gr.Markdown("Tailor your resume for specific job opportunities.")
|
| 394 |
with gr.Row():
|
| 395 |
with gr.Column():
|
| 396 |
+
customize_title = gr.Textbox(
|
| 397 |
+
label="Job Title",
|
| 398 |
+
placeholder="Senior Python Developer"
|
| 399 |
+
)
|
| 400 |
+
customize_company = gr.Textbox(
|
| 401 |
+
label="Company",
|
| 402 |
+
placeholder="Tech Inc"
|
| 403 |
+
)
|
| 404 |
+
customize_req = gr.Textbox(
|
| 405 |
+
label="Requirements",
|
| 406 |
+
placeholder="Python, Docker, AWS",
|
| 407 |
+
lines=2
|
| 408 |
+
)
|
| 409 |
customize_btn = gr.Button("β¨ Customize", variant="primary")
|
| 410 |
with gr.Column():
|
| 411 |
customize_output = gr.Markdown(value="### Customized resume will appear here...")
|
| 412 |
|
| 413 |
+
customize_btn.click(
|
| 414 |
+
fn=customize_resume_interface,
|
| 415 |
+
inputs=[customize_title, customize_company, customize_req],
|
| 416 |
+
outputs=customize_output
|
| 417 |
+
)
|
| 418 |
|
| 419 |
with gr.Tab("π― Classify Job"):
|
| 420 |
gr.Markdown("Check job relevance to your skills.")
|
| 421 |
with gr.Row():
|
| 422 |
with gr.Column():
|
| 423 |
+
classify_title = gr.Textbox(
|
| 424 |
+
label="Job Title",
|
| 425 |
+
placeholder="ML Engineer"
|
| 426 |
+
)
|
| 427 |
+
classify_req = gr.Textbox(
|
| 428 |
+
label="Requirements",
|
| 429 |
+
placeholder="Python, PyTorch",
|
| 430 |
+
lines=2
|
| 431 |
+
)
|
| 432 |
classify_btn = gr.Button("π― Classify", variant="primary")
|
| 433 |
with gr.Column():
|
| 434 |
classify_output = gr.Markdown(value="### Results will appear here...")
|
| 435 |
|
| 436 |
+
classify_btn.click(
|
| 437 |
+
fn=classify_job_interface,
|
| 438 |
+
inputs=[classify_title, classify_req],
|
| 439 |
+
outputs=classify_output
|
| 440 |
+
)
|
| 441 |
|
| 442 |
with gr.Tab("βΉοΈ About"):
|
| 443 |
gr.Markdown("""
|
|
|
|
| 463 |
logger.info("β Gradio interface built successfully\n")
|
| 464 |
|
| 465 |
# ============================================================================
|
| 466 |
+
# LAUNCH - FIXED FOR GRADIO COMPATIBILITY
|
| 467 |
# ============================================================================
|
| 468 |
|
| 469 |
if __name__ == "__main__":
|
|
|
|
| 471 |
logger.info("Access at: http://0.0.0.0:7860\n")
|
| 472 |
|
| 473 |
try:
|
| 474 |
+
# FIXED: Removed invalid 'concurrency_count' parameter
|
| 475 |
+
# Using only valid parameters for Gradio 4.0+
|
| 476 |
+
demo.launch(
|
| 477 |
server_name="0.0.0.0",
|
| 478 |
server_port=7860,
|
| 479 |
show_error=True,
|