Spaces:
Sleeping
Sleeping
Upload 7 files
Browse files- .env +1 -0
- app.py +112 -0
- branding.json +26 -0
- profile-of-hereandnowai.txt +116 -0
- program.py +94 -0
- requirements.txt +7 -0
- style.css +144 -0
.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
GEMINI_API_KEY=AIzaSyDSL9xo3NtjEqOREGkSmJr2wm-Obrqu2xU
|
app.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ui.py
|
| 2 |
+
# Gradio Web Interface for Caramel AI
|
| 3 |
+
|
| 4 |
+
import gradio as gr
|
| 5 |
+
import json
|
| 6 |
+
import os
|
| 7 |
+
from program import get_response, extract_text_from_file
|
| 8 |
+
|
| 9 |
+
# --- SETUP & BRANDING ---
|
| 10 |
+
try:
|
| 11 |
+
branding_path = os.path.join(os.path.dirname(__file__), "branding.json")
|
| 12 |
+
with open(branding_path, "r", encoding="utf-8") as f:
|
| 13 |
+
brand_info = json.load(f)["brand"]
|
| 14 |
+
except FileNotFoundError:
|
| 15 |
+
brand_info = { "organizationName": "Caramel AI", "slogan": "AI HR Manager", "logo": {"title": ""}, "colors": {"primary": "#F0E68C", "secondary": "#8B4513"}, "email": "contact@example.com", "mobile": "N/A", "website": "#", "socialMedia": {"linkedin": "#", "github": "#", "x": "#"}}
|
| 16 |
+
|
| 17 |
+
primary_color = brand_info["colors"]["primary"]
|
| 18 |
+
secondary_color = brand_info["colors"]["secondary"]
|
| 19 |
+
|
| 20 |
+
# --- CSS INJECTION ---
|
| 21 |
+
try:
|
| 22 |
+
css_path = os.path.join(os.path.dirname(__file__), "style.css")
|
| 23 |
+
with open(css_path, "r", encoding="utf-8") as f:
|
| 24 |
+
css_template = f.read()
|
| 25 |
+
final_css = f"""
|
| 26 |
+
<style>
|
| 27 |
+
:root {{
|
| 28 |
+
--brand-primary: {primary_color};
|
| 29 |
+
--brand-secondary: {secondary_color};
|
| 30 |
+
}}
|
| 31 |
+
{css_template}
|
| 32 |
+
</style>
|
| 33 |
+
"""
|
| 34 |
+
except FileNotFoundError:
|
| 35 |
+
print("Warning: style.css not found.")
|
| 36 |
+
final_css = ""
|
| 37 |
+
|
| 38 |
+
# --- FIXED: JAVASCRIPT VARIABLE DEFINITION WAS MISSING ---
|
| 39 |
+
js_trigger_file_click = """
|
| 40 |
+
() => {
|
| 41 |
+
// Find the hidden file input element and click it
|
| 42 |
+
document.querySelector('#file-uploader input[type="file"]').click();
|
| 43 |
+
}
|
| 44 |
+
"""
|
| 45 |
+
|
| 46 |
+
js_theme_toggle = """
|
| 47 |
+
() => {
|
| 48 |
+
document.body.classList.toggle('dark');
|
| 49 |
+
const theme_btn = document.querySelector('#theme-btn button');
|
| 50 |
+
if (document.body.classList.contains('dark')) {
|
| 51 |
+
theme_btn.textContent = '☀️ Light Mode';
|
| 52 |
+
} else {
|
| 53 |
+
theme_btn.textContent = '🌙 Dark Mode';
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
"""
|
| 57 |
+
|
| 58 |
+
# --- GRADIO INTERFACE ---
|
| 59 |
+
with gr.Blocks(css=final_css, title=brand_info["organizationName"]) as caramel_ai:
|
| 60 |
+
gr.HTML(f"""<div id="header"><img src="{brand_info['logo']['title']}" alt="Logo"><h2>{brand_info['organizationName']}</h2><p>{brand_info['slogan']}</p></div>""")
|
| 61 |
+
|
| 62 |
+
file_context_state = gr.State("")
|
| 63 |
+
chatbot = gr.Chatbot(height=550, label="Caramel AI Chat", type="messages")
|
| 64 |
+
status_display = gr.Markdown("Status: Ready")
|
| 65 |
+
|
| 66 |
+
file_uploader = gr.File(label="Upload File", file_count='single', file_types=['.txt', '.pdf'], elem_id="file-uploader")
|
| 67 |
+
|
| 68 |
+
with gr.Row(elem_id="input-row"):
|
| 69 |
+
with gr.Column(min_width=50, elem_id="attachment-btn-container"):
|
| 70 |
+
attachment_btn = gr.Button("📎")
|
| 71 |
+
msg_box = gr.Textbox(placeholder="Ask a question or upload a file...", show_label=False, container=False, scale=8, elem_id="msg-box")
|
| 72 |
+
send_btn = gr.Button("Ask", variant="primary", scale=1)
|
| 73 |
+
|
| 74 |
+
with gr.Row():
|
| 75 |
+
memory_switch = gr.Checkbox(label="Remember Conversation", value=True)
|
| 76 |
+
clear_btn = gr.Button("🧹 Clear All")
|
| 77 |
+
theme_btn = gr.Button("🌙 Dark Mode", elem_id="theme-btn")
|
| 78 |
+
|
| 79 |
+
# --- UI LOGIC FUNCTIONS ---
|
| 80 |
+
def process_file(file_obj, chat_history):
|
| 81 |
+
if not file_obj: return "Status: File upload failed.", "", chat_history
|
| 82 |
+
extracted_text = extract_text_from_file(file_obj)
|
| 83 |
+
if "Error:" in extracted_text: return extracted_text, None, chat_history
|
| 84 |
+
status = f"✅ **Processed:** `{os.path.basename(file_obj.name)}`"
|
| 85 |
+
history = chat_history + [{"role": "assistant", "content": f"I've read '{os.path.basename(file_obj.name)}'. Ask me anything about it."}]
|
| 86 |
+
return status, extracted_text, history
|
| 87 |
+
|
| 88 |
+
def respond(message, chat_history, memory_enabled, file_context):
|
| 89 |
+
if not message.strip(): return "", chat_history, file_context
|
| 90 |
+
history_for_api = chat_history if memory_enabled else []
|
| 91 |
+
api_history = [{"role": "model" if t["role"] == "assistant" else t["role"], "parts": [t["content"]]} for t in history_for_api]
|
| 92 |
+
context = (f"Based ONLY on the context from the document below, answer the user's question.\n\n"
|
| 93 |
+
f"--- DOCUMENT CONTEXT ---\n{file_context}\n\n--- USER QUESTION ---\n{message}") if file_context else message
|
| 94 |
+
bot_response = get_response(context, api_history)
|
| 95 |
+
history = chat_history + [{"role": "user", "content": message}, {"role": "assistant", "content": bot_response}]
|
| 96 |
+
return "", history, file_context
|
| 97 |
+
|
| 98 |
+
def clear_all():
|
| 99 |
+
return [], "", None, "Status: Ready", None
|
| 100 |
+
|
| 101 |
+
# --- EVENT LISTENERS ---
|
| 102 |
+
attachment_btn.click(fn=None, js=js_trigger_file_click)
|
| 103 |
+
theme_btn.click(fn=None, js=js_theme_toggle)
|
| 104 |
+
file_uploader.upload(process_file, inputs=[file_uploader, chatbot], outputs=[status_display, file_context_state, chatbot])
|
| 105 |
+
send_btn.click(respond, inputs=[msg_box, chatbot, memory_switch, file_context_state], outputs=[msg_box, chatbot, file_context_state])
|
| 106 |
+
msg_box.submit(respond, inputs=[msg_box, chatbot, memory_switch, file_context_state], outputs=[msg_box, chatbot, file_context_state])
|
| 107 |
+
clear_btn.click(clear_all, inputs=[], outputs=[chatbot, msg_box, file_context_state, status_display, file_uploader])
|
| 108 |
+
|
| 109 |
+
gr.HTML(f"""<div id="footer">...</div>""")
|
| 110 |
+
|
| 111 |
+
if __name__ == "__main__":
|
| 112 |
+
caramel_ai.launch()
|
branding.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"brand":
|
| 3 |
+
{
|
| 4 |
+
"organizationName": "CHATBOT",
|
| 5 |
+
"website": "https://google.com",
|
| 6 |
+
"email": "info@hereandnowai.com",
|
| 7 |
+
"mobile": "+91 996 296 1000",
|
| 8 |
+
"slogan": "designed with passion for innovation",
|
| 9 |
+
"colors": {"primary": "#FFDF00", "secondary": "#004040"},
|
| 10 |
+
"logo":
|
| 11 |
+
{
|
| 12 |
+
"title": "https://raw.githubusercontent.com/KURUPRASATH-J/AI-PROJECT-images/main/title_new.jpg",
|
| 13 |
+
"favicon": "https://raw.githubusercontent.com/KURUPRASATH-J/AI-PROJECT-images/main/favicon.jpg"}, "chatbot": {"avatar": "https://raw.githubusercontent.com/KURUPRASATH-J/AI-PROJECT-images/main/avatar.png", "face": "https://raw.githubusercontent.com/KURUPRASATH-J/AI-PROJECT-images/main/face.png"
|
| 14 |
+
},
|
| 15 |
+
|
| 16 |
+
"socialMedia":
|
| 17 |
+
{
|
| 18 |
+
"blog": "https://hereandnowai.com/blog",
|
| 19 |
+
"linkedin": "https://www.linkedin.com/company/hereandnowai/",
|
| 20 |
+
"instagram": "https://instagram.com/hereandnow_ai",
|
| 21 |
+
"github": "https://github.com/hereandnowai",
|
| 22 |
+
"x": "https://x.com/hereandnow_ai",
|
| 23 |
+
"youtube": "https://youtube.com/@hereandnow_ai"
|
| 24 |
+
}
|
| 25 |
+
}
|
| 26 |
+
}
|
profile-of-hereandnowai.txt
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# PASTE THE CLEANED PLAIN TEXT OF YOUR PROSPECTUS HERE
|
| 2 |
+
# Example snippet:
|
| 3 |
+
|
| 4 |
+
About HERE AND NOW AI
|
| 5 |
+
HERE AND NOW AI is India’s leading autonomous Artificial Intelligence Research Institute, dedicated to transforming the way AI is taught, researched, and applied. It is a brainchild of Deepti Balagopal and Ruthran Raghavan, who envisioned a future where AI education is not limited to coders but accessible to every learner — whether they’re from engineering, business, science, or the arts.
|
| 6 |
+
Born from the success of HERE AND NOW – The Language Institute (est. 2011), which redefined language learning in India, HERE AND NOW AI was founded in 2018 with a mission to disrupt traditional education through AI innovation. Our core initiatives lie in:
|
| 7 |
+
* AI Education: Delivering industry-ready, practical AI programs for students
|
| 8 |
+
* Research & Innovation: Exploring cutting-edge LLMs, RAG frameworks, and autonomous agents
|
| 9 |
+
* Automation: Building intelligent systems that power real-world enterprises and academic institutions
|
| 10 |
+
We believe that every college in India can be an AI-powered campus, and we are on a mission to make that happen.
|
| 11 |
+
|
| 12 |
+
Vision & Mission
|
| 13 |
+
Our Vision
|
| 14 |
+
To build a generation of AI-native graduates and researchers empowered with real-world skills and global exposure, through India’s first fully autonomous AI professor.
|
| 15 |
+
Our Mission
|
| 16 |
+
* Deliver AI education to 1 lakh students by 2030
|
| 17 |
+
* Sign MoUs with 100+ colleges for long-term collaboration
|
| 18 |
+
* Build AI as a Service (AIaaS) solutions for corporates using student talent
|
| 19 |
+
* Create open-access tools that empower learners and educators with AI
|
| 20 |
+
HERE AND NOW AI stands for innovation with inclusivity. Whether you're from an arts stream or an engineering background — we are here to level the playing field with AI.
|
| 21 |
+
|
| 22 |
+
Value-Added Courses Overview
|
| 23 |
+
We proudly offer two high-impact AI programs designed for value addition in colleges. These are flexible, certification-backed, and tailored to academic timetables.
|
| 24 |
+
|
| 25 |
+
1. Business Analytics with AI
|
| 26 |
+
For: Non-technical students – BBA, BCom, BA, BSc, MBA, MCA, ME
|
| 27 |
+
Prerequisites: None
|
| 28 |
+
This course introduces students to the world of data-driven business intelligence through Python, visualization tools, and cutting-edge AI platforms like ChatGPT, Claude, and Gemini.
|
| 29 |
+
Students will learn:
|
| 30 |
+
* How to clean and analyze data using Python
|
| 31 |
+
* How to interpret and visualize insights with Pandas, Matplotlib
|
| 32 |
+
* How AI can enhance decision-making in HR, Finance, Marketing
|
| 33 |
+
* Real-world project: Creating a dashboard or report powered by AI tools
|
| 34 |
+
Why this course matters: In the modern job market, even non-tech graduates are expected to have basic data literacy. This course bridges that gap while giving them an AI edge.
|
| 35 |
+
|
| 36 |
+
2. Full-Stack AI Developer Program
|
| 37 |
+
For: Technical students – BE, BTech, BCA, MCA, MSc IT, ME
|
| 38 |
+
Prerequisites: Basic familiarity with programming logic
|
| 39 |
+
This project-oriented course teaches students to build AI-powered applications end-to-end using the latest in LLM technology.
|
| 40 |
+
Students will explore:
|
| 41 |
+
* Python fundamentals + API development (Flask, FastAPI)
|
| 42 |
+
* Working with OpenAI, Claude, Gemini through API integration
|
| 43 |
+
* RAG (Retrieval-Augmented Generation), LangChain, Vector DBs
|
| 44 |
+
* Deploying AI apps on cloud platforms (GCP, Vercel)
|
| 45 |
+
* Final Capstone: Build your own AI Chatbot or Assistant
|
| 46 |
+
Why this course matters: Students not only learn AI concepts — they deploy real applications. It builds confidence, improves resumes, and gives them a head start in interviews or internships.
|
| 47 |
+
|
| 48 |
+
Business Analytics with AI: Curriculum
|
| 49 |
+
Total Duration: 30 hours | Mode: Online/Offline/Hybrid
|
| 50 |
+
Eligibility: Any UG/PG student (non-tech or mixed)
|
| 51 |
+
Module Breakdown:
|
| 52 |
+
1. Getting Started with Python – No coding experience? No problem. We begin at zero.
|
| 53 |
+
2. Data Analysis with Pandas & NumPy – Learn how to work with datasets, filter and prepare reports
|
| 54 |
+
3. Data Visualization – Turn raw data into stunning graphs using Matplotlib and Seaborn
|
| 55 |
+
4. Statistics for Business – Descriptive & Inferential Statistics for smarter decision-making
|
| 56 |
+
5. AI for Business Users – Use ChatGPT, Copilot, Claude for content, reports, and insights
|
| 57 |
+
6. Mini Project – Create a business report powered by AI tools
|
| 58 |
+
|
| 59 |
+
Full-Stack AI Developer: Curriculum
|
| 60 |
+
Total Duration: 30 hours | Mode: Project-Based | Eligibility: Tech Background Students
|
| 61 |
+
Module Breakdown:
|
| 62 |
+
1. Python + Git + IDE Setup – Get started with clean development workflow
|
| 63 |
+
2. API Development – Build backend endpoints using Flask or FastAPI
|
| 64 |
+
3. LLM Integration – Learn to work with Gemini, ChatGPT, Claude via API
|
| 65 |
+
4. LangChain & Vector Databases – Implement memory in AI using RAG
|
| 66 |
+
5. Cloud Deployment – Launch your app on GCP, Vercel with CI/CD basics
|
| 67 |
+
6. Capstone Project – Build your own AI product and present it
|
| 68 |
+
|
| 69 |
+
Delivery Format & Certification
|
| 70 |
+
Mode of Delivery:
|
| 71 |
+
* Live Classes (Online or On-Campus)
|
| 72 |
+
* AI-Powered LMS with recordings, quizzes, code labs
|
| 73 |
+
* Mentorship & Peer Discussion Forums
|
| 74 |
+
Certification:
|
| 75 |
+
* Joint Certificate from HERE AND NOW AI + Partner College
|
| 76 |
+
* Certificate includes project link and GitHub portfolio
|
| 77 |
+
Add-Ons:
|
| 78 |
+
* Career Guide PDFs, Resume Templates
|
| 79 |
+
* Code Snippets, Prompt Libraries
|
| 80 |
+
* Exclusive access to internship/freelance opportunities
|
| 81 |
+
|
| 82 |
+
Placement & Career Assistance
|
| 83 |
+
Job Readiness:
|
| 84 |
+
* Business English Training (Add-On)
|
| 85 |
+
* Soft Skills & Interview Prep (Add-On)
|
| 86 |
+
* Resume & LinkedIn Profile Optimization (Free)
|
| 87 |
+
Technical Readiness:
|
| 88 |
+
* GitHub Portfolio Guidance
|
| 89 |
+
* LeetCode Problem Solving (Add-On Module)
|
| 90 |
+
* Mock Interview Rounds
|
| 91 |
+
Network Readiness:
|
| 92 |
+
* LinkedIn Strategy: Personal Branding + Connection Funnels
|
| 93 |
+
* Monthly AI Industry Talk Sessions
|
| 94 |
+
|
| 95 |
+
Leadership Team
|
| 96 |
+
Ruthran RAGHAVAN – CEO & Chief AI Scientist
|
| 97 |
+
Visionary leader and AI educator. Invented the 108-day Business French Immersion Program. Now building India's first Autonomous AI Professor and leading AI evangelism nationwide.
|
| 98 |
+
Deepti BALAGOPAL – COO
|
| 99 |
+
Academic strategist managing operations, course quality, and outreach. She is the backbone of all institutional collaborations and program execution.
|
| 100 |
+
Balaji KAMALAKKANNAN – CTO
|
| 101 |
+
Expert in cloud, open-source LLMs, and full-stack deployment. Balaji leads all technical R&D and product integration for HERE AND NOW AI.
|
| 102 |
+
Gopalakrishnan KANNAN – CMO
|
| 103 |
+
Marketing genius with deep experience in youth outreach and digital campaigns. Gopal ensures the AI movement reaches every corner of India.
|
| 104 |
+
|
| 105 |
+
Contact & Collaboration
|
| 106 |
+
HERE AND NOW AI – Artificial Intelligence Research Institute
|
| 107 |
+
Chennai, Tamil Nadu, India
|
| 108 |
+
Website: www.hereandnowai.com
|
| 109 |
+
Email: info@hereandnowai.com
|
| 110 |
+
Phone: +91 99629 61000
|
| 111 |
+
Course Fee Structure:
|
| 112 |
+
* Business Analytics with AI: ₹5,925 / student / semester
|
| 113 |
+
* Full-Stack AI Developer Program: ₹9,925 / student / semester
|
| 114 |
+
|
| 115 |
+
Let’s Build the Future Together
|
| 116 |
+
We look forward to collaborating with your institution. Together, let’s lead India into the AI-powered future.
|
program.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# program.py
|
| 2 |
+
# AI HR Chatbot Backend for Caramel AI
|
| 3 |
+
|
| 4 |
+
import os
|
| 5 |
+
import requests
|
| 6 |
+
import google.generativeai as genai
|
| 7 |
+
from dotenv import load_dotenv
|
| 8 |
+
import PyPDF2 # <-- Add this import
|
| 9 |
+
|
| 10 |
+
# --- SETUP ---
|
| 11 |
+
# (This existing code is unchanged)
|
| 12 |
+
load_dotenv()
|
| 13 |
+
api_key = os.getenv("GEMINI_API_KEY")
|
| 14 |
+
if not api_key:
|
| 15 |
+
raise ValueError("GEMINI_API_KEY not found. Please create a .env file with your API key.")
|
| 16 |
+
genai.configure(api_key=api_key)
|
| 17 |
+
|
| 18 |
+
try:
|
| 19 |
+
print("Fetching knowledge base from URL...")
|
| 20 |
+
txt_url = "https://raw.githubusercontent.com/hereandnowai/vac/refs/heads/master/prospectus-context.txt"
|
| 21 |
+
response = requests.get(txt_url)
|
| 22 |
+
response.raise_for_status()
|
| 23 |
+
text_lines = response.text.splitlines()
|
| 24 |
+
text_context = "\n".join([line.strip() for line in text_lines if line.strip()])
|
| 25 |
+
print("✅ Knowledge base loaded successfully.")
|
| 26 |
+
except requests.RequestException as e:
|
| 27 |
+
print(f"[ERROR loading context from URL] {e}")
|
| 28 |
+
text_context = "No text context available."
|
| 29 |
+
|
| 30 |
+
system_prompt = f"""
|
| 31 |
+
You are Caramel AI, a fair and approachable Human Resources Manager.
|
| 32 |
+
Your mission is to explain workplace policies, provide general advice on employee relations,
|
| 33 |
+
and answer questions about recruitment and professional development.
|
| 34 |
+
Always promote a positive and inclusive work environment.
|
| 35 |
+
⚡ Important:
|
| 36 |
+
- Your first response in any new conversation must be to introduce yourself as:
|
| 37 |
+
“Caramel AI – AI Human Resource Manager, built at HERE AND NOW AI – Artificial Intelligence Research Institute.”
|
| 38 |
+
- You must use ONLY the provided Workplace Policy Context to answer questions. If the answer
|
| 39 |
+
is not in the context, say "I'm sorry, but that information is not available in my knowledge base."
|
| 40 |
+
--- Workplace Policy Context ---
|
| 41 |
+
{text_context}
|
| 42 |
+
"""
|
| 43 |
+
model = genai.GenerativeModel(
|
| 44 |
+
model_name="gemini-1.5-flash",
|
| 45 |
+
system_instruction=system_prompt
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
# --- CORE FUNCTION ---
|
| 49 |
+
# (This existing function is unchanged)
|
| 50 |
+
def get_response(message: str, history: list) -> str:
|
| 51 |
+
"""
|
| 52 |
+
Gets a response from the Gemini model based on a message and conversation history.
|
| 53 |
+
"""
|
| 54 |
+
conversation = history + [{"role": "user", "parts": [message]}]
|
| 55 |
+
try:
|
| 56 |
+
response = model.generate_content(conversation)
|
| 57 |
+
return response.text.strip()
|
| 58 |
+
except Exception as e:
|
| 59 |
+
print(f"Error during API call: {e}")
|
| 60 |
+
return f"⚠️ I'm sorry, I encountered an error. Please try again. Error: {e}"
|
| 61 |
+
|
| 62 |
+
# --- NEW FEATURE: FILE PROCESSING FUNCTION ---
|
| 63 |
+
def extract_text_from_file(file_obj):
|
| 64 |
+
"""
|
| 65 |
+
Extracts text from an uploaded file object (supports .txt and .pdf).
|
| 66 |
+
|
| 67 |
+
Args:
|
| 68 |
+
file_obj: A file object from Gradio's gr.File component.
|
| 69 |
+
|
| 70 |
+
Returns:
|
| 71 |
+
A string containing the extracted text or an error message.
|
| 72 |
+
"""
|
| 73 |
+
if file_obj is None:
|
| 74 |
+
return "Error: No file object received."
|
| 75 |
+
|
| 76 |
+
file_path = file_obj.name
|
| 77 |
+
print(f"Processing file: {file_path}")
|
| 78 |
+
|
| 79 |
+
try:
|
| 80 |
+
if file_path.lower().endswith('.txt'):
|
| 81 |
+
with open(file_path, 'r', encoding='utf-8') as f:
|
| 82 |
+
return f.read()
|
| 83 |
+
|
| 84 |
+
elif file_path.lower().endswith('.pdf'):
|
| 85 |
+
reader = PyPDF2.PdfReader(file_path)
|
| 86 |
+
text_chunks = [page.extract_text() for page in reader.pages if page.extract_text()]
|
| 87 |
+
return "\n".join(text_chunks)
|
| 88 |
+
|
| 89 |
+
else:
|
| 90 |
+
return "Error: Unsupported file type. Please upload a .txt or .pdf file."
|
| 91 |
+
|
| 92 |
+
except Exception as e:
|
| 93 |
+
print(f"Error processing file {file_path}: {e}")
|
| 94 |
+
return f"Error: Could not process the file. It may be corrupted. Details: {e}"
|
requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
google-generativeai
|
| 3 |
+
python-dotenv
|
| 4 |
+
requests
|
| 5 |
+
PyPDF2
|
| 6 |
+
gtts
|
| 7 |
+
pydub
|
style.css
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* --- 1. THEME VARIABLES (For Light & Dark Mode) --- */
|
| 2 |
+
:root {
|
| 3 |
+
--bg-color: #fdfdfd;
|
| 4 |
+
--primary-text-color: #2c3e50;
|
| 5 |
+
--secondary-text-color: #555;
|
| 6 |
+
--border-color: #eaeaea;
|
| 7 |
+
--shadow-color: rgba(0, 0, 0, 0.05);
|
| 8 |
+
--card-bg-color: #ffffff; /* Used for chatbot background */
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
/* Dark mode color overrides */
|
| 12 |
+
body.dark {
|
| 13 |
+
--bg-color: #1e1e1e;
|
| 14 |
+
--primary-text-color: #ecf0f1;
|
| 15 |
+
--secondary-text-color: #bdc3c7;
|
| 16 |
+
--border-color: #3a3a3a;
|
| 17 |
+
--shadow-color: rgba(0, 0, 0, 0.2);
|
| 18 |
+
--card-bg-color: #2a2a2a;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
---
|
| 22 |
+
|
| 23 |
+
/* --- 2. GENERAL STYLES (From your previous code) --- */
|
| 24 |
+
body {
|
| 25 |
+
background-color: var(--bg-color);
|
| 26 |
+
color: var(--primary-text-color);
|
| 27 |
+
font-family: 'Helvetica Neue', Arial, sans-serif;
|
| 28 |
+
transition: background-color 0.3s, color 0.3s;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
/* Header Styles */
|
| 32 |
+
#header {
|
| 33 |
+
text-align: center;
|
| 34 |
+
margin-bottom: 20px;
|
| 35 |
+
padding-bottom: 1rem;
|
| 36 |
+
border-bottom: 1px solid var(--border-color);
|
| 37 |
+
}
|
| 38 |
+
#header img {
|
| 39 |
+
max-height: 100px;
|
| 40 |
+
border-radius: 12px;
|
| 41 |
+
display: block;
|
| 42 |
+
margin: auto;
|
| 43 |
+
}
|
| 44 |
+
#header h2 {
|
| 45 |
+
margin: 10px 0 5px;
|
| 46 |
+
}
|
| 47 |
+
#header p {
|
| 48 |
+
font-size: 14px;
|
| 49 |
+
color: var(--secondary-text-color);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
---
|
| 53 |
+
|
| 54 |
+
/* --- 3. CHAT & INPUT STYLES --- */
|
| 55 |
+
|
| 56 |
+
/* Chatbot Message Styles */
|
| 57 |
+
.gr-chatbot {
|
| 58 |
+
background-color: var(--card-bg-color) !important;
|
| 59 |
+
}
|
| 60 |
+
.gr-chatbot .user, .gr-chatbot .bot {
|
| 61 |
+
border-radius: 12px;
|
| 62 |
+
box-shadow: 0 2px 5px var(--shadow-color);
|
| 63 |
+
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
| 64 |
+
}
|
| 65 |
+
.gr-chatbot .user:hover, .gr-chatbot .bot:hover {
|
| 66 |
+
transform: translateY(-3px);
|
| 67 |
+
box-shadow: 0 5px 15px var(--shadow-color);
|
| 68 |
+
}
|
| 69 |
+
.gr-chatbot .user {
|
| 70 |
+
color: black !important;
|
| 71 |
+
}
|
| 72 |
+
.gr-chatbot .bot {
|
| 73 |
+
color: white !important;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
/* Styles to place the pin icon inside the search box */
|
| 77 |
+
#input-row {
|
| 78 |
+
position: relative;
|
| 79 |
+
display: flex;
|
| 80 |
+
align-items: center;
|
| 81 |
+
}
|
| 82 |
+
#attachment-btn-container {
|
| 83 |
+
position: absolute;
|
| 84 |
+
left: 8px;
|
| 85 |
+
top: 50%;
|
| 86 |
+
transform: translateY(-50%);
|
| 87 |
+
z-index: 100;
|
| 88 |
+
}
|
| 89 |
+
#attachment-btn-container button {
|
| 90 |
+
background: transparent !important;
|
| 91 |
+
border: none !important;
|
| 92 |
+
font-size: 1.5rem !important;
|
| 93 |
+
padding: 0 4px !important;
|
| 94 |
+
color: #888;
|
| 95 |
+
}
|
| 96 |
+
#attachment-btn-container button:hover {
|
| 97 |
+
color: var(--brand-secondary);
|
| 98 |
+
}
|
| 99 |
+
#msg-box textarea {
|
| 100 |
+
padding-left: 45px !important; /* Makes space for the pin icon */
|
| 101 |
+
border-radius: 12px !important;
|
| 102 |
+
border: 1px solid var(--border-color) !important;
|
| 103 |
+
background-color: var(--bg-color) !important;
|
| 104 |
+
color: var(--primary-text-color) !important;
|
| 105 |
+
}
|
| 106 |
+
/* Highlight textbox on focus */
|
| 107 |
+
#msg-box textarea:focus {
|
| 108 |
+
border-color: var(--brand-secondary) !important;
|
| 109 |
+
box-shadow: 0 0 5px var(--brand-secondary) !important;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
/* Hides the default file uploader component */
|
| 113 |
+
#file-uploader {
|
| 114 |
+
display: none;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
---
|
| 118 |
+
|
| 119 |
+
/* --- 4. FOOTER & BUTTON STYLES --- */
|
| 120 |
+
/* Button Hover Effect (From your previous code) */
|
| 121 |
+
.gr-button:hover {
|
| 122 |
+
transform: scale(1.03);
|
| 123 |
+
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
|
| 124 |
+
transition: all 0.2s ease-in-out;
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
/* Footer Styles */
|
| 128 |
+
#footer {
|
| 129 |
+
text-align: center;
|
| 130 |
+
margin-top: 30px;
|
| 131 |
+
padding-top: 1rem;
|
| 132 |
+
font-size: 14px;
|
| 133 |
+
color: var(--secondary-text-color);
|
| 134 |
+
border-top: 1px solid var(--border-color);
|
| 135 |
+
}
|
| 136 |
+
#footer a {
|
| 137 |
+
color: var(--brand-secondary);
|
| 138 |
+
text-decoration: none;
|
| 139 |
+
transition: color 0.2s;
|
| 140 |
+
}
|
| 141 |
+
#footer a:hover {
|
| 142 |
+
color: var(--brand-primary);
|
| 143 |
+
text-decoration: underline;
|
| 144 |
+
}
|