MSGraphAPI / app.py
awacke1's picture
Update app.py
dbf031b verified
raw
history blame
14.1 kB
import os
import streamlit as st
import requests
import msal
from datetime import datetime, timedelta
import calendar
# Configuration
APPLICATION_ID_KEY = os.getenv('APPLICATION_ID_KEY')
CLIENT_SECRET_KEY = os.getenv('CLIENT_SECRET_KEY')
AUTHORITY_URL = 'https://login.microsoftonline.com/common'
REDIRECT_URI = 'https://huggingface.co/spaces/awacke1/MSGraphAPI'
# Define product to scope mapping, links, AI capabilities, and Graph solutions
PRODUCT_SCOPES = {
"πŸ“§ Outlook": {
'scopes': ['Mail.Read', 'Mail.Send'],
'link': 'https://outlook.office.com/mail/',
'ai_capabilities': "πŸ€–βœοΈ Smart email & scheduling",
'graph_solution': "πŸ“¨πŸ“… Mail, calendar & contacts API"
},
"πŸ“… Calendar": {
'scopes': ['Calendars.ReadWrite'],
'link': 'https://outlook.office.com/calendar/',
'ai_capabilities': "πŸ€–πŸ“… Smart scheduling & reminders",
'graph_solution': "πŸ“… Calendar management API"
},
"πŸ“‹ Tasks": {
'scopes': ['Tasks.ReadWrite'],
'link': 'https://to-do.office.com/tasks/',
'ai_capabilities': "πŸ€–πŸ“ Task prioritization",
'graph_solution': "βœ… Task management API"
},
"πŸ—‚οΈ OneDrive": {
'scopes': ['Files.ReadWrite.All'],
'link': 'https://onedrive.live.com/',
'ai_capabilities': "πŸ€–πŸ” Smart file organization",
'graph_solution': "πŸ“ File & folder API"
},
"πŸ“’ OneNote": {
'scopes': ['Notes.Read', 'Notes.Create'],
'link': 'https://www.onenote.com/notebooks',
'ai_capabilities': "πŸ€–πŸ“ Content suggestion & OCR",
'graph_solution': "πŸ“” Notebook & page API"
},
"πŸ“Š Excel": {
'scopes': ['Files.ReadWrite.All'],
'link': 'https://www.office.com/launch/excel',
'ai_capabilities': "πŸ€–πŸ“ˆ Data analysis & insights",
'graph_solution': "πŸ“Š Workbook & chart API"
},
"πŸ“„ Word": {
'scopes': ['Files.ReadWrite.All'],
'link': 'https://www.office.com/launch/word',
'ai_capabilities': "πŸ€–βœοΈ Smart drafting & editing",
'graph_solution': "πŸ“ Document content API"
},
"πŸ—ƒοΈ SharePoint": {
'scopes': ['Sites.Read.All', 'Sites.ReadWrite.All'],
'link': 'https://www.microsoft.com/microsoft-365/sharepoint/collaboration',
'ai_capabilities': "πŸ€–πŸ” Smart search & tagging",
'graph_solution': "🌐 Sites & lists API"
},
"πŸ“… Teams": {
'scopes': ['Team.ReadBasic.All', 'Channel.ReadBasic.All'],
'link': 'https://teams.microsoft.com/',
'ai_capabilities': "πŸ€–πŸ’¬ Meeting insights & summaries",
'graph_solution': "πŸ‘₯ Teams & chats API"
},
"πŸ’¬ Viva": {
'scopes': ['Analytics.Read'],
'link': 'https://www.microsoft.com/microsoft-viva',
'ai_capabilities': "πŸ€–πŸ“Š Personalized insights",
'graph_solution': "πŸ“ˆ Analytics & learning API"
},
"πŸš€ Power Platform": {
'scopes': ['Flow.Read.All'],
'link': 'https://powerplatform.microsoft.com/',
'ai_capabilities': "πŸ€–βš™οΈ AI-powered automation",
'graph_solution': "πŸ”§ Workflow & app API"
},
"🧠 Copilot": {
'scopes': ['Cognitive.Read'],
'link': 'https://www.microsoft.com/microsoft-365/copilot',
'ai_capabilities': "πŸ€–πŸš€ Cross-app AI assistance",
'graph_solution': "🧠 AI integration API"
},
"πŸ’‘ PowerPoint": {
'scopes': ['Files.ReadWrite.All'],
'link': 'https://www.office.com/launch/powerpoint',
'ai_capabilities': "πŸ€–πŸŽ¨ Design & coaching AI",
'graph_solution': "πŸ“Š Presentation API"
},
"πŸ“š Microsoft Bookings": {
'scopes': ['Bookings.Read.All', 'Bookings.ReadWrite.All'],
'link': 'https://outlook.office.com/bookings/',
'ai_capabilities': "πŸ€–πŸ“… Smart scheduling",
'graph_solution': "πŸ“† Booking services API"
},
"πŸ““ Loop": {
'scopes': ['Files.ReadWrite.All'],
'link': 'https://loop.microsoft.com/',
'ai_capabilities': "πŸ€–πŸ”„ Real-time collaboration AI",
'graph_solution': "πŸ” Workspace API"
},
"πŸ—£οΈ Translator": {
'scopes': ['Translation.Read'],
'link': 'https://www.microsoft.com/translator/',
'ai_capabilities': "πŸ€–πŸŒ Real-time translation",
'graph_solution': "πŸ—¨οΈ Translation services API"
},
"πŸ“‹ To Do & Planner": {
'scopes': ['Tasks.ReadWrite'],
'link': 'https://todo.microsoft.com/',
'ai_capabilities': "πŸ€–πŸ“ Smart task management",
'graph_solution': "βœ… Task & plan API"
},
"πŸ”— Azure OpenAI Service": {
'scopes': ['AzureAIServices.ReadWrite.All'],
'link': 'https://azure.microsoft.com/products/cognitive-services/openai-service/',
'ai_capabilities': "πŸ€–πŸ§  Custom AI model access",
'graph_solution': "πŸ”Œ AI model integration API"
}
}
BASE_SCOPES = ['User.Read']
def get_msal_app():
return msal.ConfidentialClientApplication(
client_id=APPLICATION_ID_KEY,
client_credential=CLIENT_SECRET_KEY,
authority=AUTHORITY_URL
)
def get_access_token(code):
client_instance = get_msal_app()
try:
result = client_instance.acquire_token_by_authorization_code(
code=code,
scopes=st.session_state.get('request_scopes', BASE_SCOPES),
redirect_uri=REDIRECT_URI
)
if 'access_token' in result:
return result['access_token']
else:
raise Exception(f"Error acquiring token: {result.get('error_description')}")
except Exception as e:
st.error(f"Exception in get_access_token: {str(e)}")
raise
def make_api_call(access_token, endpoint, method='GET', data=None):
headers = {'Authorization': f'Bearer {access_token}', 'Content-Type': 'application/json'}
url = f'https://graph.microsoft.com/v1.0/{endpoint}'
if method == 'GET':
response = requests.get(url, headers=headers)
elif method == 'POST':
response = requests.post(url, headers=headers, json=data)
else:
raise ValueError(f"Unsupported method: {method}")
if response.status_code in [200, 201]:
return response.json()
else:
st.error(f"API call failed: {response.status_code} - {response.text}")
return None
def handle_outlook_integration(access_token):
st.subheader("πŸ“§ Outlook Integration")
st.markdown(f"[Open Outlook]({PRODUCT_SCOPES['πŸ“§ Outlook']['link']})")
emails = make_api_call(access_token, 'me/messages?$top=10&$orderby=receivedDateTime desc')
if emails and 'value' in emails:
for email in emails['value']:
with st.expander(f"From: {email['from']['emailAddress']['name']} - Subject: {email['subject']}"):
st.write(f"Received: {email['receivedDateTime']}")
st.write(f"Body: {email['bodyPreview']}")
else:
st.write("No emails found or unable to fetch emails.")
def handle_calendar_integration(access_token):
st.subheader("πŸ“… Calendar Integration")
st.markdown(f"[Open Calendar]({PRODUCT_SCOPES['πŸ“… Calendar']['link']})")
# Get the current month's start and end dates
now = datetime.now()
start_of_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
end_of_month = start_of_month.replace(month=start_of_month.month % 12 + 1, day=1) - timedelta(days=1)
events = make_api_call(access_token, f"me/calendarView?startDateTime={start_of_month.isoformat()}&endDateTime={end_of_month.isoformat()}&$orderby=start/dateTime")
if events and 'value' in events:
# Create a calendar view
cal = calendar.monthcalendar(now.year, now.month)
st.write(f"Calendar for {now.strftime('%B %Y')}")
# Create a placeholder for each day
day_placeholders = {}
for week in cal:
cols = st.columns(7)
for i, day in enumerate(week):
if day != 0:
day_placeholders[day] = cols[i].empty()
day_placeholders[day].write(f"**{day}**")
# Populate the calendar with events
for event in events['value']:
start_date = datetime.fromisoformat(event['start']['dateTime'][:-1]) # Remove 'Z' from the end
day = start_date.day
if day in day_placeholders:
day_placeholders[day].write(f"{start_date.strftime('%H:%M')} - {event['subject']}")
else:
st.write("No events found or unable to fetch events.")
st.write("Add a new event:")
event_subject = st.text_input("Event Subject")
event_date = st.date_input("Event Date")
event_time = st.time_input("Event Time")
if st.button("Add Event"):
event_start = datetime.combine(event_date, event_time)
event_end = event_start + timedelta(hours=1)
new_event = {
"subject": event_subject,
"start": {
"dateTime": event_start.isoformat(),
"timeZone": "UTC"
},
"end": {
"dateTime": event_end.isoformat(),
"timeZone": "UTC"
}
}
result = make_api_call(access_token, 'me/events', method='POST', data=new_event)
if result:
st.success("Event added successfully!")
else:
st.error("Failed to add event.")
def handle_tasks_integration(access_token):
st.subheader("πŸ“‹ Tasks Integration")
st.markdown(f"[Open Tasks]({PRODUCT_SCOPES['πŸ“‹ Tasks']['link']})")
tasks = make_api_call(access_token, 'me/todo/lists')
if tasks and 'value' in tasks:
default_list = next((list for list in tasks['value'] if list['wellknownListName'] == 'defaultList'), None)
if default_list:
tasks = make_api_call(access_token, f"me/todo/lists/{default_list['id']}/tasks")
if tasks and 'value' in tasks:
for task in tasks['value']:
st.write(f"Task: {task['title']}")
st.write(f"Status: {'Completed' if task['status'] == 'completed' else 'Not Completed'}")
st.write("---")
else:
st.write("No tasks found or unable to fetch tasks.")
else:
st.write("Default task list not found.")
else:
st.write("Unable to fetch task lists.")
st.write("Add a new task:")
task_title = st.text_input("Task Title")
if st.button("Add Task"):
new_task = {
"title": task_title
}
result = make_api_call(access_token, f"me/todo/lists/{default_list['id']}/tasks", method='POST', data=new_task)
if result:
st.success("Task added successfully!")
else:
st.error("Failed to add task.")
def handle_onedrive_integration(access_token):
st.subheader("πŸ—‚οΈ OneDrive Integration")
st.markdown(f"[Open OneDrive]({PRODUCT_SCOPES['πŸ—‚οΈ OneDrive']['link']})")
files = make_api_call(access_token, 'me/drive/root/children')
if files and 'value' in files:
for file in files['value']:
st.write(f"Name: {file['name']}")
st.write(f"Type: {'Folder' if 'folder' in file else 'File'}")
st.write(f"Last Modified: {file['lastModifiedDateTime']}")
st.write("---")
else:
st.write("No files found or unable to fetch files.")
def main():
st.title("πŸ¦„ MS Graph API with AI & Cloud Integration for M365")
st.sidebar.title("πŸ“ M365 Products")
st.sidebar.write("Select products to integrate:")
selected_products = {}
for product in PRODUCT_SCOPES.keys():
selected = st.sidebar.checkbox(product)
if selected:
selected_products[product] = True
request_scopes = BASE_SCOPES.copy()
for product in selected_products:
request_scopes.extend(PRODUCT_SCOPES[product]['scopes'])
request_scopes = list(set(request_scopes))
st.session_state['request_scopes'] = request_scopes
if 'access_token' not in st.session_state:
client_instance = get_msal_app()
auth_url = client_instance.get_authorization_request_url(
scopes=request_scopes,
redirect_uri=REDIRECT_URI
)
st.write('πŸ‘‹ Please [click here]({}) to log in and authorize the app.'.format(auth_url))
query_params = st.query_params
if 'code' in query_params:
code = query_params.get('code')
st.write('πŸ”‘ Authorization Code Obtained:', code[:10] + '...')
try:
access_token = get_access_token(code)
st.session_state['access_token'] = access_token
st.success("Access token acquired successfully!")
st.rerun()
except Exception as e:
st.error(f"Error acquiring access token: {str(e)}")
st.stop()
else:
access_token = st.session_state['access_token']
user_info = make_api_call(access_token, 'me')
if user_info:
st.sidebar.write(f"πŸ‘‹ Hello, {user_info.get('displayName', 'User')}!")
if selected_products:
for product in selected_products:
if product == "πŸ“§ Outlook":
handle_outlook_integration(access_token)
elif product == "πŸ“… Calendar":
handle_calendar_integration(access_token)
elif product == "πŸ“‹ Tasks":
handle_tasks_integration(access_token)
elif product == "πŸ—‚οΈ OneDrive":
handle_onedrive_integration(access_token)
# Add more product integrations here
else:
st.write("No products selected. Please select products from the sidebar.")
if __name__ == "__main__":
main()