Spaces:
Sleeping
Sleeping
Add user token input - users provide their own HF token
Browse files
app.py
CHANGED
|
@@ -14,40 +14,43 @@ from langchain_core.messages import SystemMessage, HumanMessage
|
|
| 14 |
# Load environment variables
|
| 15 |
load_dotenv()
|
| 16 |
|
| 17 |
-
# Global state - Initialize
|
| 18 |
rag = None
|
| 19 |
-
agent = None
|
| 20 |
-
initialized = False
|
| 21 |
-
|
| 22 |
-
def initialize_on_startup():
|
| 23 |
-
"""Initialize system automatically on startup."""
|
| 24 |
-
global rag, agent, initialized
|
| 25 |
|
|
|
|
|
|
|
|
|
|
| 26 |
data_dir = Path("./data")
|
| 27 |
-
|
| 28 |
if not data_dir.exists():
|
| 29 |
-
return
|
| 30 |
-
|
| 31 |
try:
|
| 32 |
rag = ProjectRAG(data_dir)
|
| 33 |
rag.load_and_index()
|
| 34 |
-
|
| 35 |
-
if rag.meetings:
|
| 36 |
-
agent = ProjectAgent(rag)
|
| 37 |
-
initialized = True
|
| 38 |
except Exception as e:
|
| 39 |
-
print(f"
|
|
|
|
| 40 |
|
| 41 |
-
# Initialize on module load
|
| 42 |
-
|
| 43 |
|
| 44 |
-
def chat(message, history, project_filter):
|
| 45 |
"""Process chat message."""
|
| 46 |
-
if not
|
| 47 |
-
yield "⚠️
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
return
|
| 49 |
|
| 50 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
# Add project context if specified
|
| 52 |
if project_filter and project_filter != "All Projects":
|
| 53 |
enhanced_prompt = f"[Project: {project_filter}] {message}"
|
|
@@ -57,30 +60,31 @@ def chat(message, history, project_filter):
|
|
| 57 |
response = agent.query(enhanced_prompt)
|
| 58 |
yield response
|
| 59 |
except Exception as e:
|
| 60 |
-
yield f"❌ Error: {str(e)}"
|
| 61 |
|
| 62 |
def get_projects():
|
| 63 |
"""Get list of projects."""
|
| 64 |
-
if not
|
| 65 |
return ["All Projects"]
|
| 66 |
|
| 67 |
projects = rag.get_all_projects()
|
| 68 |
return ["All Projects"] + projects
|
| 69 |
|
| 70 |
-
def structure_meeting(project_name, meeting_title, meeting_date, participants, meeting_text):
|
| 71 |
"""Structure meeting notes using AI."""
|
|
|
|
|
|
|
|
|
|
| 72 |
if not project_name or not meeting_text:
|
| 73 |
return "❌ Please provide both project name and meeting notes"
|
| 74 |
|
| 75 |
try:
|
| 76 |
-
# Use HF Inference API
|
| 77 |
-
# HF Spaces provides token as HF_TOKEN or HUGGING_FACE_HUB_TOKEN
|
| 78 |
-
hf_token = os.getenv("HF_TOKEN") or os.getenv("HUGGING_FACE_HUB_TOKEN")
|
| 79 |
endpoint = HuggingFaceEndpoint(
|
| 80 |
repo_id="meta-llama/Llama-3.2-3B-Instruct",
|
| 81 |
temperature=0.3,
|
| 82 |
max_new_tokens=1024,
|
| 83 |
-
huggingfacehub_api_token=hf_token
|
| 84 |
)
|
| 85 |
llm = ChatHuggingFace(llm=endpoint)
|
| 86 |
|
|
@@ -172,6 +176,21 @@ with gr.Blocks(title="Sherlock: AI Project Assistant", theme=gr.themes.Soft(), c
|
|
| 172 |
with gr.Tab("💬 Chat"):
|
| 173 |
gr.Markdown("### Ask questions about your projects")
|
| 174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
# Project selection dropdown
|
| 176 |
project_dropdown = gr.Dropdown(
|
| 177 |
label="Select Project",
|
|
@@ -217,13 +236,13 @@ with gr.Blocks(title="Sherlock: AI Project Assistant", theme=gr.themes.Soft(), c
|
|
| 217 |
submit_btn = gr.Button("Send", variant="primary", scale=1)
|
| 218 |
clear_btn = gr.Button("Clear", scale=1)
|
| 219 |
|
| 220 |
-
def respond(message, chat_history, project):
|
| 221 |
if not message:
|
| 222 |
return chat_history, ""
|
| 223 |
|
| 224 |
# Get bot response
|
| 225 |
bot_message = ""
|
| 226 |
-
for response_chunk in chat(message, chat_history, project):
|
| 227 |
bot_message = response_chunk
|
| 228 |
|
| 229 |
# Add to history as tuple
|
|
@@ -233,13 +252,13 @@ with gr.Blocks(title="Sherlock: AI Project Assistant", theme=gr.themes.Soft(), c
|
|
| 233 |
|
| 234 |
submit_btn.click(
|
| 235 |
fn=respond,
|
| 236 |
-
inputs=[msg, chatbot, project_dropdown],
|
| 237 |
outputs=[chatbot, msg]
|
| 238 |
)
|
| 239 |
|
| 240 |
msg.submit(
|
| 241 |
fn=respond,
|
| 242 |
-
inputs=[msg, chatbot, project_dropdown],
|
| 243 |
outputs=[chatbot, msg]
|
| 244 |
)
|
| 245 |
|
|
@@ -249,6 +268,13 @@ with gr.Blocks(title="Sherlock: AI Project Assistant", theme=gr.themes.Soft(), c
|
|
| 249 |
with gr.Tab("📤 Upload Meeting"):
|
| 250 |
gr.Markdown("### Upload plain text meeting notes and let AI structure them")
|
| 251 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
# Project selection with toggle
|
| 253 |
with gr.Row():
|
| 254 |
with gr.Column():
|
|
@@ -312,15 +338,15 @@ Charlie is blocked waiting for API credentials.""",
|
|
| 312 |
structure_btn = gr.Button("🤖 Structure Meeting with AI", variant="primary")
|
| 313 |
structure_output = gr.Markdown(label="Structured Output")
|
| 314 |
|
| 315 |
-
def structure_meeting_wrapper(mode, existing_proj, new_proj, title, date, participants, text):
|
| 316 |
"""Wrapper to handle both project modes."""
|
| 317 |
# Determine which project name to use
|
| 318 |
project_name = existing_proj if mode == "Use Existing Project" else new_proj
|
| 319 |
-
return structure_meeting(project_name, title, date, participants, text)
|
| 320 |
|
| 321 |
structure_btn.click(
|
| 322 |
fn=structure_meeting_wrapper,
|
| 323 |
-
inputs=[project_mode, existing_project, new_project, upload_title, upload_date, upload_participants, upload_text],
|
| 324 |
outputs=structure_output
|
| 325 |
)
|
| 326 |
|
|
|
|
| 14 |
# Load environment variables
|
| 15 |
load_dotenv()
|
| 16 |
|
| 17 |
+
# Global state - Initialize RAG only (not agent)
|
| 18 |
rag = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
+
def initialize_rag():
|
| 21 |
+
"""Initialize RAG system (embeddings only, no LLM needed)."""
|
| 22 |
+
global rag
|
| 23 |
data_dir = Path("./data")
|
|
|
|
| 24 |
if not data_dir.exists():
|
| 25 |
+
return False
|
|
|
|
| 26 |
try:
|
| 27 |
rag = ProjectRAG(data_dir)
|
| 28 |
rag.load_and_index()
|
| 29 |
+
return True
|
|
|
|
|
|
|
|
|
|
| 30 |
except Exception as e:
|
| 31 |
+
print(f"RAG initialization error: {e}")
|
| 32 |
+
return False
|
| 33 |
|
| 34 |
+
# Initialize RAG on module load
|
| 35 |
+
initialize_rag()
|
| 36 |
|
| 37 |
+
def chat(message, history, project_filter, hf_token):
|
| 38 |
"""Process chat message."""
|
| 39 |
+
if not hf_token or hf_token.strip() == "":
|
| 40 |
+
yield "⚠️ Please enter your HuggingFace token first (get one at https://huggingface.co/settings/tokens)"
|
| 41 |
+
return
|
| 42 |
+
|
| 43 |
+
if not rag:
|
| 44 |
+
yield "⚠️ System not initialized. Please check the data directory."
|
| 45 |
return
|
| 46 |
|
| 47 |
try:
|
| 48 |
+
# Set token in environment for this request
|
| 49 |
+
os.environ["HF_TOKEN"] = hf_token.strip()
|
| 50 |
+
|
| 51 |
+
# Create agent with user's token
|
| 52 |
+
agent = ProjectAgent(rag)
|
| 53 |
+
|
| 54 |
# Add project context if specified
|
| 55 |
if project_filter and project_filter != "All Projects":
|
| 56 |
enhanced_prompt = f"[Project: {project_filter}] {message}"
|
|
|
|
| 60 |
response = agent.query(enhanced_prompt)
|
| 61 |
yield response
|
| 62 |
except Exception as e:
|
| 63 |
+
yield f"❌ Error: {str(e)}\n\nMake sure your HuggingFace token is valid."
|
| 64 |
|
| 65 |
def get_projects():
|
| 66 |
"""Get list of projects."""
|
| 67 |
+
if not rag:
|
| 68 |
return ["All Projects"]
|
| 69 |
|
| 70 |
projects = rag.get_all_projects()
|
| 71 |
return ["All Projects"] + projects
|
| 72 |
|
| 73 |
+
def structure_meeting(project_name, meeting_title, meeting_date, participants, meeting_text, hf_token):
|
| 74 |
"""Structure meeting notes using AI."""
|
| 75 |
+
if not hf_token or hf_token.strip() == "":
|
| 76 |
+
return "❌ Please enter your HuggingFace token first"
|
| 77 |
+
|
| 78 |
if not project_name or not meeting_text:
|
| 79 |
return "❌ Please provide both project name and meeting notes"
|
| 80 |
|
| 81 |
try:
|
| 82 |
+
# Use HF Inference API with user's token
|
|
|
|
|
|
|
| 83 |
endpoint = HuggingFaceEndpoint(
|
| 84 |
repo_id="meta-llama/Llama-3.2-3B-Instruct",
|
| 85 |
temperature=0.3,
|
| 86 |
max_new_tokens=1024,
|
| 87 |
+
huggingfacehub_api_token=hf_token.strip()
|
| 88 |
)
|
| 89 |
llm = ChatHuggingFace(llm=endpoint)
|
| 90 |
|
|
|
|
| 176 |
with gr.Tab("💬 Chat"):
|
| 177 |
gr.Markdown("### Ask questions about your projects")
|
| 178 |
|
| 179 |
+
# HuggingFace Token input
|
| 180 |
+
with gr.Row():
|
| 181 |
+
hf_token_chat = gr.Textbox(
|
| 182 |
+
label="🔑 HuggingFace Token (Required)",
|
| 183 |
+
placeholder="Enter your HF token from https://huggingface.co/settings/tokens",
|
| 184 |
+
type="password",
|
| 185 |
+
scale=3
|
| 186 |
+
)
|
| 187 |
+
gr.Markdown("""
|
| 188 |
+
**Get a free token:**
|
| 189 |
+
1. Go to [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)
|
| 190 |
+
2. Create a new token with "Read" permissions
|
| 191 |
+
3. Paste it here
|
| 192 |
+
""", scale=1)
|
| 193 |
+
|
| 194 |
# Project selection dropdown
|
| 195 |
project_dropdown = gr.Dropdown(
|
| 196 |
label="Select Project",
|
|
|
|
| 236 |
submit_btn = gr.Button("Send", variant="primary", scale=1)
|
| 237 |
clear_btn = gr.Button("Clear", scale=1)
|
| 238 |
|
| 239 |
+
def respond(message, chat_history, project, token):
|
| 240 |
if not message:
|
| 241 |
return chat_history, ""
|
| 242 |
|
| 243 |
# Get bot response
|
| 244 |
bot_message = ""
|
| 245 |
+
for response_chunk in chat(message, chat_history, project, token):
|
| 246 |
bot_message = response_chunk
|
| 247 |
|
| 248 |
# Add to history as tuple
|
|
|
|
| 252 |
|
| 253 |
submit_btn.click(
|
| 254 |
fn=respond,
|
| 255 |
+
inputs=[msg, chatbot, project_dropdown, hf_token_chat],
|
| 256 |
outputs=[chatbot, msg]
|
| 257 |
)
|
| 258 |
|
| 259 |
msg.submit(
|
| 260 |
fn=respond,
|
| 261 |
+
inputs=[msg, chatbot, project_dropdown, hf_token_chat],
|
| 262 |
outputs=[chatbot, msg]
|
| 263 |
)
|
| 264 |
|
|
|
|
| 268 |
with gr.Tab("📤 Upload Meeting"):
|
| 269 |
gr.Markdown("### Upload plain text meeting notes and let AI structure them")
|
| 270 |
|
| 271 |
+
# HuggingFace Token input
|
| 272 |
+
hf_token_upload = gr.Textbox(
|
| 273 |
+
label="🔑 HuggingFace Token (Required)",
|
| 274 |
+
placeholder="Enter your HF token from https://huggingface.co/settings/tokens",
|
| 275 |
+
type="password"
|
| 276 |
+
)
|
| 277 |
+
|
| 278 |
# Project selection with toggle
|
| 279 |
with gr.Row():
|
| 280 |
with gr.Column():
|
|
|
|
| 338 |
structure_btn = gr.Button("🤖 Structure Meeting with AI", variant="primary")
|
| 339 |
structure_output = gr.Markdown(label="Structured Output")
|
| 340 |
|
| 341 |
+
def structure_meeting_wrapper(mode, existing_proj, new_proj, title, date, participants, text, token):
|
| 342 |
"""Wrapper to handle both project modes."""
|
| 343 |
# Determine which project name to use
|
| 344 |
project_name = existing_proj if mode == "Use Existing Project" else new_proj
|
| 345 |
+
return structure_meeting(project_name, title, date, participants, text, token)
|
| 346 |
|
| 347 |
structure_btn.click(
|
| 348 |
fn=structure_meeting_wrapper,
|
| 349 |
+
inputs=[project_mode, existing_project, new_project, upload_title, upload_date, upload_participants, upload_text, hf_token_upload],
|
| 350 |
outputs=structure_output
|
| 351 |
)
|
| 352 |
|