Skip to content

Commit ae4880d

Browse files
author
nitinaggarwal-databricks
committed
updated code for marketplace readiness
1 parent e819786 commit ae4880d

File tree

17 files changed

+19846
-22
lines changed

17 files changed

+19846
-22
lines changed

agent_genie/app.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ command: [
22
"uvicorn",
33
"app:app",
44
"--host",
5-
"127.0.0.1",
5+
"0.0.0.0",
66
"--port",
77
"8000"
88
]
99
env:
1010
- name: "SPACE_ID"
11-
value: genie-space
11+
valueFrom: genie-space
1212
- name: "SERVING_ENDPOINT_NAME"
13-
value: serving-endpoint
13+
valueFrom: serving-endpoint
14+
- name: "TAVILY_API_KEY"
15+
value: "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"

agent_genie/manual_ai_content.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
description,
3636
ai_classify(description, ARRAY('clothing', 'shoes', 'accessories', 'furniture')) AS category
3737
FROM
38-
products
39-
;""",
38+
products;
39+
shoes""",
4040

4141
"ai_extract": """Syntax
4242
ai_extract(content, labels)
@@ -101,15 +101,13 @@
101101
Summer Bike Sale: Grab Your Dream Bike at 20% Off!
102102
103103
> SELECT
104-
question,
104+
'What is the impact of AI on reducing hospital readmissions?',
105105
ai_gen(
106-
'You are a teacher. Answer the students question in 50 words: ' || question
106+
'Answer the question: ' || 'What is the impact of AI on reducing hospital readmissions?'
107107
) AS answer
108108
FROM
109-
questions
110-
;
111-
112-
""",
109+
questions;
110+
AI helps identify high-risk patients early by analyzing EHR data, lifestyle, and treatment patterns. Predictive models enable proactive care coordination and follow-up, reducing avoidable hospital readmissions and improving patient outcomes while optimizing resource utilization and lowering costs.""",
113111
"ai_mask": """Syntax
114112
ai_mask(content, labels)
115113
@@ -244,10 +242,8 @@
244242
horizon => '2016-03-31',
245243
time_col => 'ds',
246244
value_col => 'revenue'
247-
);
248-
249-
""",
250-
"ai_query": """Syntax
245+
);""",
246+
"ai_query": """Syntax
251247
To query an endpoint that serves a foundation model:
252248
253249
ai_query(endpoint, request)
@@ -262,4 +258,4 @@
262258
FROM uc_catalog.schema.table;
263259
264260
""" # For general predictive queries
265-
}
261+
}

agent_genie/templates/index.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,7 +1348,7 @@ <h1>Databricks Genie++ Omni-Analytics Platform</h1>
13481348
</div>
13491349

13501350
<div class="section-description">
1351-
A multi-agent AI engine that answers questions, forecasts trends, classifies data, summarizes records, translates languages, and recommends next-best actions.
1351+
A multi-agent AI engine that answers questions, forecasts trends, classifies data, summarizes records, translates languages, and recommends next-best actions. For any questions or feedback, please reach out to nitin.aggarwal@databricks.com
13521352
</div>
13531353

13541354
<!-- Collapsible Elements Container -->
@@ -1430,8 +1430,8 @@ <h1>Databricks Genie++ Omni-Analytics Platform</h1>
14301430
<button onclick="askFixedQuestion('Summarize the record into Spanish')">
14311431
Summarize the record into Spanish
14321432
</button>
1433-
<button onclick="askFixedQuestion('Classify each record into categories: High, Medium, and Low. Also, specify the reason')">
1434-
Classify each record using categories: High, Medium, and Low. Also, specify the reason
1433+
<button onclick="askFixedQuestion('Classify each record into categories: High, Medium, Low and specify the reason')">
1434+
Classify each record into categories: High, Medium, Low and specify the reason
14351435
</button>
14361436
<button onclick="askFixedQuestion('Summarize the record, and suggest one next best action for the analyst supporting the business')">
14371437
Summarize the record, and suggest one next best action for the analyst supporting the business
@@ -2645,4 +2645,4 @@ <h1>Databricks Genie++ Omni-Analytics Platform</h1>
26452645
});
26462646
</script>
26472647
</body>
2648-
</html>
2648+
</html>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

agent_genie_git_old/CODEOWNERS

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# There can be only one CODEOWNERS file in the repo for clarity. See https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-file-location
2+
3+
# Catch-all rule comes first
4+
5+
* @databrickslabs/sandbox-write
6+
7+
# Specific owners are listed last. Please keep this list in the alphabetical order
8+
9+
acceptance @nfx @alexott
10+
conversational-agent-app @vivian-xie-db @yuanchaoma-db
11+
database-diagram-builder @alexott
12+
downstreams @nfx @alexott
13+
feature-registry-app @yang-chengg @mparkhe @mingyangge-db @stephanielu5
14+
go-libs @nfx @alexott
15+
ip_access_list_analyzer @alexott
16+
ka-chat-bot @taiga-db
17+
metascan @nfx @alexott
18+
runtime-packages @nfx @alexott
19+
sql_migration_copilot @robertwhiffin
20+
tacklebox @Jonathan-Choi
21+
uc-catalog-cloning @esiol-db @vasco-lopes
22+
.github @nfx @alexott @gueniai

agent_genie_git_old/app.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import os
2+
import json
3+
import requests
4+
from flask import Flask, render_template, request, jsonify
5+
from databricks.sdk.core import Config
6+
from databricks.sdk import WorkspaceClient
7+
from databricks.sdk.service.serving import ChatMessage, ChatMessageRole
8+
9+
# Initialize Flask app
10+
app = Flask(__name__, static_folder='static', template_folder='static')
11+
12+
cfg = Config()
13+
client = WorkspaceClient()
14+
15+
# Model serving endpoint name
16+
ENDPOINT_NAME = "agents_ws_vfc_demo-sch_vfc_demo-fashion_merchandising_agent"
17+
18+
@app.route('/')
19+
def index():
20+
"""Serve the main HTML page"""
21+
return render_template('index.html')
22+
23+
@app.route('/api/chat', methods=['POST'])
24+
def chat():
25+
"""Handle chat requests and forward to model serving endpoint using Databricks SDK"""
26+
try:
27+
# Get the message history from the request
28+
data = request.get_json()
29+
messages = data.get('messages', [])
30+
31+
if not messages:
32+
return jsonify({'error': 'No messages provided'}), 400
33+
34+
# Convert messages to ChatMessage objects
35+
chat_messages = []
36+
for msg in messages:
37+
role = msg.get('role', 'user')
38+
content = msg.get('content', '')
39+
40+
# Map roles to ChatMessageRole enum
41+
if role == 'user':
42+
chat_role = ChatMessageRole.USER
43+
elif role == 'assistant':
44+
chat_role = ChatMessageRole.ASSISTANT
45+
elif role == 'system':
46+
chat_role = ChatMessageRole.SYSTEM
47+
else:
48+
chat_role = ChatMessageRole.USER # Default to user
49+
50+
chat_messages.append(ChatMessage(role=chat_role, content=content))
51+
52+
# Get user information for logging
53+
user_email = request.headers.get('X-Forwarded-Email')
54+
app.logger.info(f"Making request to model endpoint for user: {user_email}")
55+
56+
# Make request to model serving endpoint using Databricks SDK
57+
response = client.serving_endpoints.query(
58+
name=ENDPOINT_NAME,
59+
messages=chat_messages
60+
)
61+
62+
# Extract the response content
63+
if response and hasattr(response, 'choices') and response.choices:
64+
# Get the first choice
65+
choice = response.choices[0]
66+
if hasattr(choice, 'message') and choice.message:
67+
result_content = choice.message.content
68+
return jsonify({'content': result_content})
69+
else:
70+
return jsonify({'error': 'No message content in response'}), 500
71+
else:
72+
return jsonify({'error': 'No response choices received'}), 500
73+
74+
except Exception as e:
75+
error_msg = str(e)
76+
app.logger.error(f"Error calling model endpoint: {error_msg}")
77+
78+
# Handle specific error types
79+
if "authentication" in error_msg.lower() or "unauthorized" in error_msg.lower():
80+
return jsonify({
81+
'error': 'Authentication failed. Your Databricks token may have expired.',
82+
'details': 'Please refresh the page or log in again.'
83+
}), 401
84+
elif "permission" in error_msg.lower() or "forbidden" in error_msg.lower():
85+
return jsonify({
86+
'error': 'Access denied. You may not have permission to access this model endpoint.',
87+
'details': 'Please contact your Databricks administrator.'
88+
}), 403
89+
elif "timeout" in error_msg.lower():
90+
return jsonify({'error': 'Request timed out. Please try again.'}), 504
91+
else:
92+
return jsonify({
93+
'error': f'Unexpected error: {error_msg}',
94+
'details': 'Please try again or contact support if the issue persists.'
95+
}), 500
96+
97+
@app.route('/health')
98+
def health():
99+
"""Health check endpoint"""
100+
user_email = request.headers.get('X-Forwarded-Email')
101+
102+
try:
103+
# Test the client connection
104+
client.current_user.me()
105+
client_healthy = True
106+
except Exception as e:
107+
client_healthy = False
108+
app.logger.error(f"Client health check failed: {str(e)}")
109+
110+
return jsonify({
111+
'status': 'healthy',
112+
'client_authenticated': client_healthy,
113+
'user_email': user_email if user_email else 'anonymous',
114+
'endpoint_name': ENDPOINT_NAME
115+
})
116+
117+
@app.route('/api/debug')
118+
def debug():
119+
"""Debug endpoint to check authentication and endpoint status"""
120+
headers_info = {
121+
'X-Forwarded-Access-Token': 'present' if request.headers.get('X-Forwarded-Access-Token') else 'missing',
122+
'X-Forwarded-Email': request.headers.get('X-Forwarded-Email', 'not provided'),
123+
'User-Agent': request.headers.get('User-Agent', 'not provided'),
124+
'Authorization': 'present' if request.headers.get('Authorization') else 'missing'
125+
}
126+
127+
try:
128+
# Check if we can access the serving endpoint
129+
endpoint_info = client.serving_endpoints.get(name=ENDPOINT_NAME)
130+
endpoint_status = endpoint_info.state.value if endpoint_info.state else 'unknown'
131+
except Exception as e:
132+
endpoint_status = f'error: {str(e)}'
133+
134+
try:
135+
# Check current user
136+
current_user = client.current_user.me()
137+
user_info = current_user.user_name if current_user else 'unknown'
138+
except Exception as e:
139+
user_info = f'error: {str(e)}'
140+
141+
return jsonify({
142+
'message': 'Debug information for Databricks App',
143+
'headers': headers_info,
144+
'endpoint_name': ENDPOINT_NAME,
145+
'endpoint_status': endpoint_status,
146+
'current_user': user_info,
147+
'sdk_config': {
148+
'host': cfg.host if hasattr(cfg, 'host') else 'not set',
149+
'auth_type': cfg.auth_type if hasattr(cfg, 'auth_type') else 'not set'
150+
}
151+
})
152+
153+
if __name__ == '__main__':
154+
# Get port from environment variable or default to 8080
155+
port = int(os.environ.get('PORT', 8080))
156+
app.run(host='0.0.0.0', port=port, debug=False)

agent_genie_git_old/app.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
command: [
2+
"uvicorn",
3+
"app:app",
4+
"--host",
5+
"127.0.0.1",
6+
"--port",
7+
"8000"
8+
]
9+
env:
10+
- name: "SPACE_ID"
11+
value: "01f03de6df76113387ccc36242e6c804"
12+
- name: "SERVING_ENDPOINT_NAME"
13+
value: "databricks-gpt-oss-120b"
14+
- name: "TAVILY_API_KEY"
15+
value: "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"

agent_genie_git_old/databricks.yml

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
bundle:
2+
name: agent-genie-app
3+
4+
variables:
5+
project_name:
6+
description: "Display name for the app"
7+
default: "agent-genie"
8+
9+
# Env-only fallback; will also be persisted to a secret by the installer job if possible
10+
tavily_api_key:
11+
description: "Tavily API key (installer job will try to store in a secret scope)"
12+
default: ""
13+
14+
# Where to persist the secret (customize if you already have a scope)
15+
secret_scope:
16+
description: "Workspace secret scope to store Tavily key"
17+
default: "agent_genie_secrets"
18+
19+
secret_key:
20+
description: "Secret key name for Tavily key inside the scope"
21+
default: "TAVILY_API_KEY"
22+
23+
environment:
24+
description: "Deployment environment (dev, staging, prod)"
25+
default: "dev"
26+
27+
targets:
28+
dev:
29+
default: true
30+
mode: development
31+
32+
resources:
33+
apps:
34+
agent_genie:
35+
name: "${var.project_name}"
36+
description: "FastAPI app with Genie + Serving Endpoint integration"
37+
source_code_path: "."
38+
39+
command: [
40+
"uvicorn",
41+
"app:app",
42+
"--host",
43+
"127.0.0.1",
44+
"--port",
45+
"8000"
46+
]
47+
48+
# Inject env for your app at runtime
49+
env:
50+
- name: "SPACE_ID"
51+
value_from: "genie-space"
52+
- name: "SERVING_ENDPOINT_NAME"
53+
value_from: "serving-endpoint"
54+
- name: "TAVILY_API_KEY"
55+
value: "${var.tavily_api_key}" # app can use this directly; secret is optional hardening
56+
57+
# --- App Resources (end-user picks these at install) ---
58+
app_resources:
59+
- key: "serving-endpoint"
60+
serving_endpoint_spec:
61+
permission: "CAN_QUERY"
62+
- key: "genie-space"
63+
genie_space_spec:
64+
permission: "CAN_RUN"
65+
66+
# --- User Authorized Scopes (Preview) ---
67+
user_authorized_scopes:
68+
- "sql"
69+
- "dashboards.genie"
70+
- "files.files"
71+
- "serving.serving-endpoints"
72+
- "vectorsearch.vector-search-indexes"
73+
- "catalog.connections"
74+
75+
# --- Installer job to persist Tavily key into a secret and write optional config ---
76+
jobs:
77+
install_app:
78+
name: "${var.project_name} - Install/Configure"
79+
tasks:
80+
- task_key: configure_app
81+
notebook_task:
82+
notebook_path: "./notebooks/setup_app" # create this notebook
83+
base_parameters:
84+
TAVILY_API_KEY: "${var.tavily_api_key}"
85+
SECRET_SCOPE: "${var.secret_scope}"
86+
SECRET_KEY: "${var.secret_key}"
87+
# Add compute for your workspace (example placeholders):
88+
# existing_cluster_id: "<your-cluster-id>"
89+
# OR:
90+
# job_clusters:
91+
# - job_cluster_key: "install_cluster"
92+
# new_cluster:
93+
# spark_version: "14.3.x-scala2.12"
94+
# node_type_id: "i3.xlarge"
95+
# num_workers: 0

0 commit comments

Comments
 (0)