from fastapi import FastAPI
from pydantic import BaseModel
from typing import Dict, List
import gradio as gr
import pandas as pd
import json
from src.core import *
app = FastAPI(
title="Insight Finder",
description="Find relevant technologies from a problem",
)
class InputData(BaseModel):
problem: str
class InputConstraints(BaseModel):
constraints: Dict[str, str]
# This schema defines the structure for a single technology object
class Technology(BaseModel):
"""Represents a single technology entry with its details."""
title: str
purpose: str
key_components: str
advantages: str
limitations: str
id: int
# This schema defines the root structure of the JSON
class TechnologyData(BaseModel):
"""Represents the top-level object containing a list of technologies."""
technologies: List[Technology]
@app.post("/process", response_model=TechnologyData)
async def process(data: InputData):
result = process_input(data, global_tech, global_tech_embeddings)
return {"technologies": result}
@app.post("/process-constraints", response_model=TechnologyData)
async def process_constraints(constraints: InputConstraints):
result = process_input_from_constraints(constraints.constraints, global_tech, global_tech_embeddings)
return {"technologies": result}
def make_json_serializable(data):
if isinstance(data, dict):
return {k: make_json_serializable(v) for k, v in data.items()}
elif isinstance(data, list):
return [make_json_serializable(item) for item in data]
elif isinstance(data, tuple):
return tuple(make_json_serializable(item) for item in data)
elif hasattr(data, 'item'):
return float(data.item())
else:
return data
# --- Helper functions to format HTML outputs ---
def format_constraints_html(constraints: dict) -> str:
html_content = "
"
for title, description in constraints.items():
html_content += f"""
Retrieved Constraints
"""
html_content += "
"
return html_content
def format_best_combinations_html(combinations_data: list) -> str:
html_content = ""
for i, combination in enumerate(combinations_data):
problem_title = combination.get("problem", {}).get("title", f"Problem {i+1}")
technologies = combination.get("technologies", [])
html_content += f"""
Retrieved Constraints
{problem_title}
"""
for tech_info_score in technologies:
tech_info = tech_info_score[0] # The dictionary part
if isinstance(tech_info, dict):
html_content += f"""
The 5 Best Technology Combinations Found
{tech_info.get('title', 'N/A')}
Purpose: {tech_info.get('purpose', 'N/A')}
Components: {tech_info.get('key_components', 'N/A')}
Advantages: {tech_info.get('advantages', 'N/A')}
Limitations: {tech_info.get('limitations', 'N/A')}
"""
html_content += """
"""
html_content += "
"
return html_content
def format_final_technologies_html(technologies_list: list) -> str:
html_content = ""
for tech_info in technologies_list:
if isinstance(tech_info, dict):
html_content += f"""
The best technology combinations for each constraint
{tech_info.get('title', 'N/A')}
Purpose: {tech_info.get('purpose', 'N/A')}
Components: {tech_info.get('key_components', 'N/A')}
Advantages: {tech_info.get('advantages', 'N/A')}
Limitations: {tech_info.get('limitations', 'N/A')}
"""
html_content += "
"
return html_content
def process_input_gradio(problem_description: str):
"""
Processes the input problem description step-by-step for Gradio.
Returns all intermediate results.
"""
# Step 1: Set Prompt
prompt = set_prompt(problem_description)
# Step 2: Retrieve Constraints
constraints = retrieve_constraints(prompt)
# Step 3: Stem Constraints
constraints_stemmed = stem(constraints, "constraints")
save_dataframe(pd.DataFrame({"stemmed_constraints": constraints_stemmed}), "constraints_stemmed.xlsx")
print(constraints_stemmed)
# Step 4: Global Tech (already loaded, just acknowledge)
# save_dataframe(global_tech_df, "global_tech.xlsx") # This is already done implicitly by loading
# Step 5: Get Contrastive Similarities
result_similarities, matrix = get_contrastive_similarities(
constraints_stemmed, global_tech, global_tech_embeddings
)
save_to_pickle(result_similarities)
# Step 6: Find Best List Combinations
best_combinations = find_best_list_combinations(constraints_stemmed, global_tech, matrix)
# Step 7: Select Technologies
best_technologies_id = select_technologies(best_combinations)
# Step 8: Get Technologies by ID
best_technologies = get_technologies_by_id(best_technologies_id, global_tech)
print(constraints)
print(best_combinations)
print(best_technologies)
# Format outputs for Gradio
# For Constraints:
constraints_html = format_constraints_html(constraints)
# For Best Combinations:
best_combinations_html = format_best_combinations_html(best_combinations)
# For Final Technologies:
final_technologies_html = format_final_technologies_html(best_technologies)
return (
prompt,
constraints_html, # Output HTML for constraints
best_combinations_html, # Output HTML for best combinations
", ".join(map(str, best_technologies_id)), # Still a simple text list
final_technologies_html # Output HTML for final technologies
)
# --- Gradio Interface Setup ---
input_problem = gr.Textbox(
label="Enter Problem Description",
placeholder="e.g., Develop a secure and scalable e-commerce platform with real-time analytics."
)
output_prompt = gr.Textbox(label="1. Generated Prompt", interactive=False)
output_constraints = gr.HTML(label="2. Retrieved Constraints") # Changed to HTML
output_best_combinations = gr.HTML(label="7. Best Technology Combinations Found") # Changed to HTML
output_selected_ids = gr.Textbox(label="8. Selected Technology IDs", interactive=False)
output_final_technologies = gr.HTML(label="9. Final Best Technologies") # Changed to HTML
# Custom CSS for a professional look and specific output styling
custom_css = """
/* General Body and Font Styling */
body {
font-family: 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
color: #333;
background-color: #f0f2f5;
}
/* Header Styling */
.gradio-container h1 {
color: #0056b3; /* A deep blue for the main title */
text-align: center;
margin-bottom: 10px;
font-weight: 600;
font-size: 2.5em;
text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
}
.gradio-container h2 {
color: #007bff; /* A slightly lighter blue for subtitles */
text-align: center;
margin-top: 0;
margin-bottom: 30px;
font-weight: 400;
font-size: 1.2em;
}
/* Card-like styling for individual components */
.gradio-container .gr-box {
background-color: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
padding: 20px;
margin-bottom: 20px;
border: 1px solid #e0e0e0;
}
/* Input Textbox Styling */
.gradio-container input[type="text"],
.gradio-container textarea {
border: 1px solid #ced4da;
border-radius: 8px;
padding: 12px 15px;
font-size: 1em;
color: #495057;
transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
}
.gradio-container input[type="text"]:focus,
.gradio-container textarea:focus {
border-color: #007bff;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
outline: none;
}
/* Button Styling */
.gradio-container button {
background-color: #28a745; /* A vibrant green for action */
color: white;
border: none;
border-radius: 8px;
padding: 12px 25px;
font-size: 1.1em;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s ease-in-out, transform 0.1s ease-in-out;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.gradio-container button:hover {
background-color: #218838; /* Darker green on hover */
transform: translateY(-2px);
}
.gradio-container button:active {
transform: translateY(0);
}
/* Labels for outputs */
.gradio-container label {
font-weight: 600;
color: #495057;
margin-bottom: 8px;
display: block; /* Ensure labels are on their own line */
font-size: 1.1em;
}
/* --- Specific Styling for Outputs --- */
/* 2. Retrieved Constraints Styling */
.constraints-container {
padding: 15px;
background-color: #f8f9fa;
border-radius: 8px;
border: 1px solid #e9ecef;
font-family: 'Georgia', serif; /* Different font */
line-height: 1.6;
max-height: 300px;
overflow-y: auto;
}
.constraint-item {
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px dashed #e0e0e0;
}
.constraint-item:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.constraint-title {
font-weight: bold;
color: #004085; /* Darker blue for constraint titles */
font-size: 1.1em;
}
.constraint-description {
color: #333;
font-size: 1em;
}
/* 7. Best Technology Combinations Found & 9. Final Best Technologies Styling */
.combinations-outer-container, .final-tech-container {
padding: 15px;
background-color: #f8f9fa;
border-radius: 8px;
border: 1px solid #e9ecef;
max-height: 500px; /* Adjust as needed */
overflow-y: auto;
font-family: 'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif; /* Different font */
}
.problem-card {
background-color: #ffffff;
border: 1px solid #cfe2ff; /* Light blue border for problem card */
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
}
.problem-card-title {
color: #0056b3; /* Deep blue for problem title */
font-size: 1.4em;
margin-top: 0;
margin-bottom: 15px;
border-bottom: 2px solid #cfe2ff;
padding-bottom: 10px;
}
.technologies-inner-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); /* Responsive grid for technologies */
gap: 15px;
}
.technology-card, .final-tech-card {
background-color: #f0faff; /* Very light blue for technology cards */
border: 1px solid #b0d9ff; /* Slightly darker blue border */
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
transition: transform 0.2s ease-in-out;
}
.technology-card:hover, .final-tech-card:hover {
transform: translateY(-3px);
}
.tech-card-title, .final-tech-title {
color: #007bff; /* Gradio's primary blue */
font-size: 1.2em;
margin-top: 0;
margin-bottom: 10px;
font-weight: 600;
}
.technology-card p, .final-tech-card p {
font-size: 0.95em;
line-height: 1.5;
margin-bottom: 5px;
color: #555;
}
.technology-card p strong, .final-tech-card p strong {
color: #004085; /* Darker blue for bold labels */
}
/* Responsive adjustments */
@media (max-width: 768px) {
.gradio-container {
padding: 15px;
}
.gradio-container h1 {
font-size: 2em;
}
.gradio-container button {
width: 100%;
padding: 15px;
}
.technologies-inner-container {
grid-template-columns: 1fr; /* Stack columns on smaller screens */
}
}
"""
# Create the Gradio Blocks demo with custom theme and CSS
with gr.Blocks(
theme=gr.themes.Soft(),
css=custom_css
) as gradio_app_blocks:
gr.Markdown("# Insight Finder: Step-by-Step Technology Selection")
gr.Markdown("## Enter a problem description to see how relevant technologies are identified through various processing steps.")
with gr.Row():
with gr.Column(scale=2):
input_problem.render()
with gr.Column(scale=1):
gr.Markdown("Click to start the analysis:"),
process_button = gr.Button("Process Problem", elem_id="process_button")
gr.Markdown("---")
gr.Markdown("### Processing Steps & Results:")
with gr.Row():
with gr.Column():
output_prompt.render()
output_constraints.render() # Renders HTML
with gr.Column():
output_selected_ids.render() # This remains a Textbox
output_best_combinations.render() # Renders HTML
output_final_technologies.render() # Renders HTML
process_button.click(
fn=process_input_gradio,
inputs=input_problem,
outputs=[
output_prompt,
output_constraints,
output_best_combinations,
output_selected_ids,
output_final_technologies
]
)
gr.mount_gradio_app(app, gradio_app_blocks, path="/gradio")