arcade-google-slides 0.1.1__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- arcade_google_slides/__init__.py +2 -0
- arcade_google_slides/tools/__init__.py +4 -0
- arcade_google_slides/{file_picker.py → tools/file_picker.py} +14 -6
- arcade_google_slides/tools/get.py +1 -4
- arcade_google_slides/tools/search.py +1 -14
- arcade_google_slides/tools/system_context.py +37 -0
- arcade_google_slides/who_am_i_util.py +81 -0
- {arcade_google_slides-0.1.1.dist-info → arcade_google_slides-1.1.0.dist-info}/METADATA +1 -1
- arcade_google_slides-1.1.0.dist-info/RECORD +17 -0
- arcade_google_slides/decorators.py +0 -24
- arcade_google_slides/templates.py +0 -5
- arcade_google_slides-0.1.1.dist-info/RECORD +0 -17
- {arcade_google_slides-0.1.1.dist-info → arcade_google_slides-1.1.0.dist-info}/WHEEL +0 -0
- {arcade_google_slides-0.1.1.dist-info → arcade_google_slides-1.1.0.dist-info}/licenses/LICENSE +0 -0
arcade_google_slides/__init__.py
CHANGED
|
@@ -2,6 +2,7 @@ from arcade_google_slides.tools import (
|
|
|
2
2
|
comment_on_presentation,
|
|
3
3
|
create_presentation,
|
|
4
4
|
create_slide,
|
|
5
|
+
generate_google_file_picker_url,
|
|
5
6
|
get_presentation_as_markdown,
|
|
6
7
|
list_presentation_comments,
|
|
7
8
|
search_presentations,
|
|
@@ -14,4 +15,5 @@ __all__ = [
|
|
|
14
15
|
"search_presentations",
|
|
15
16
|
"comment_on_presentation",
|
|
16
17
|
"list_presentation_comments",
|
|
18
|
+
"generate_google_file_picker_url",
|
|
17
19
|
]
|
|
@@ -3,10 +3,12 @@ from arcade_google_slides.tools.comment import (
|
|
|
3
3
|
list_presentation_comments,
|
|
4
4
|
)
|
|
5
5
|
from arcade_google_slides.tools.create import create_presentation, create_slide
|
|
6
|
+
from arcade_google_slides.tools.file_picker import generate_google_file_picker_url
|
|
6
7
|
from arcade_google_slides.tools.get import get_presentation_as_markdown
|
|
7
8
|
from arcade_google_slides.tools.search import (
|
|
8
9
|
search_presentations,
|
|
9
10
|
)
|
|
11
|
+
from arcade_google_slides.tools.system_context import who_am_i
|
|
10
12
|
|
|
11
13
|
__all__ = [
|
|
12
14
|
"create_presentation",
|
|
@@ -15,4 +17,6 @@ __all__ = [
|
|
|
15
17
|
"search_presentations",
|
|
16
18
|
"comment_on_presentation",
|
|
17
19
|
"list_presentation_comments",
|
|
20
|
+
"generate_google_file_picker_url",
|
|
21
|
+
"who_am_i",
|
|
18
22
|
]
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import json
|
|
3
|
+
from typing import Annotated
|
|
3
4
|
|
|
4
|
-
from arcade_tdk import ToolContext, ToolMetadataKey
|
|
5
|
+
from arcade_tdk import ToolContext, ToolMetadataKey, tool
|
|
6
|
+
from arcade_tdk.auth import Google
|
|
5
7
|
from arcade_tdk.errors import ToolExecutionError
|
|
6
8
|
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
@tool(
|
|
11
|
+
requires_auth=Google(),
|
|
12
|
+
requires_metadata=[ToolMetadataKey.CLIENT_ID, ToolMetadataKey.COORDINATOR_URL],
|
|
13
|
+
)
|
|
14
|
+
def generate_google_file_picker_url(
|
|
15
|
+
context: ToolContext,
|
|
16
|
+
) -> Annotated[dict, "Google File Picker URL for user file selection and permission granting"]:
|
|
9
17
|
"""Generate a Google File Picker URL for user-driven file selection and authorization.
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
This tool generates a URL that directs the end-user to a Google File Picker interface where
|
|
12
20
|
where they can select or upload Google Drive files. Users can grant permission to access their
|
|
13
21
|
Drive files, providing a secure and authorized way to interact with their files.
|
|
14
22
|
|
|
@@ -17,8 +25,8 @@ def generate_google_file_picker_url(context: ToolContext) -> dict:
|
|
|
17
25
|
(Requested entity was not found) or permission errors. Once the user completes the file
|
|
18
26
|
picker flow, the prior tool can be retried.
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
Suggest this tool to users when they are surprised or confused that the file they are
|
|
29
|
+
searching for or attempting to access cannot be found.
|
|
22
30
|
"""
|
|
23
31
|
client_id = context.get_metadata(ToolMetadataKey.CLIENT_ID)
|
|
24
32
|
client_id_parts = client_id.split("-")
|
|
@@ -44,6 +52,6 @@ def generate_google_file_picker_url(context: ToolContext) -> dict:
|
|
|
44
52
|
"url": url,
|
|
45
53
|
"llm_instructions": (
|
|
46
54
|
"Instruct the user to click the following link to open the Google Drive File Picker. "
|
|
47
|
-
|
|
55
|
+
"This will allow them to select files and grant access permissions: {url}"
|
|
48
56
|
),
|
|
49
57
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
from typing import Annotated, cast
|
|
2
2
|
|
|
3
|
-
from arcade_tdk import ToolContext,
|
|
3
|
+
from arcade_tdk import ToolContext, tool
|
|
4
4
|
from arcade_tdk.auth import Google
|
|
5
5
|
|
|
6
|
-
from arcade_google_slides.decorators import with_filepicker_fallback
|
|
7
6
|
from arcade_google_slides.types import Presentation
|
|
8
7
|
from arcade_google_slides.utils import build_slides_service, convert_presentation_to_markdown
|
|
9
8
|
|
|
@@ -14,9 +13,7 @@ from arcade_google_slides.utils import build_slides_service, convert_presentatio
|
|
|
14
13
|
"https://www.googleapis.com/auth/drive.file",
|
|
15
14
|
],
|
|
16
15
|
),
|
|
17
|
-
requires_metadata=[ToolMetadataKey.CLIENT_ID, ToolMetadataKey.COORDINATOR_URL],
|
|
18
16
|
)
|
|
19
|
-
@with_filepicker_fallback
|
|
20
17
|
async def get_presentation_as_markdown(
|
|
21
18
|
context: ToolContext,
|
|
22
19
|
presentation_id: Annotated[str, "The ID of the presentation to retrieve."],
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
from typing import Annotated, Any
|
|
2
2
|
|
|
3
|
-
from arcade_tdk import ToolContext,
|
|
3
|
+
from arcade_tdk import ToolContext, tool
|
|
4
4
|
from arcade_tdk.auth import Google
|
|
5
5
|
|
|
6
6
|
from arcade_google_slides.enum import OrderBy
|
|
7
|
-
from arcade_google_slides.file_picker import generate_google_file_picker_url
|
|
8
|
-
from arcade_google_slides.templates import optional_file_picker_instructions_template
|
|
9
7
|
from arcade_google_slides.utils import (
|
|
10
8
|
build_drive_service,
|
|
11
9
|
build_files_list_params,
|
|
@@ -20,7 +18,6 @@ from arcade_google_slides.utils import (
|
|
|
20
18
|
requires_auth=Google(
|
|
21
19
|
scopes=["https://www.googleapis.com/auth/drive.file"],
|
|
22
20
|
),
|
|
23
|
-
requires_metadata=[ToolMetadataKey.CLIENT_ID, ToolMetadataKey.COORDINATOR_URL],
|
|
24
21
|
)
|
|
25
22
|
async def search_presentations(
|
|
26
23
|
context: ToolContext,
|
|
@@ -112,19 +109,9 @@ async def search_presentations(
|
|
|
112
109
|
if not pagination_token or len(batch) < page_size:
|
|
113
110
|
break
|
|
114
111
|
|
|
115
|
-
file_picker_response = generate_google_file_picker_url(
|
|
116
|
-
context,
|
|
117
|
-
)
|
|
118
|
-
|
|
119
112
|
return {
|
|
120
113
|
"presentations_count": len(files),
|
|
121
114
|
"presentations": files,
|
|
122
|
-
"file_picker": {
|
|
123
|
-
"url": file_picker_response["url"],
|
|
124
|
-
"llm_instructions": optional_file_picker_instructions_template.format(
|
|
125
|
-
url=file_picker_response["url"]
|
|
126
|
-
),
|
|
127
|
-
},
|
|
128
115
|
"llm_instructions": (
|
|
129
116
|
"If the results were not satisfactory, then inform the user that "
|
|
130
117
|
"you can also search across all of their shared drives."
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import Annotated, Any
|
|
2
|
+
|
|
3
|
+
from arcade_tdk import ToolContext, tool
|
|
4
|
+
from arcade_tdk.auth import Google
|
|
5
|
+
|
|
6
|
+
from arcade_google_slides.utils import build_slides_service
|
|
7
|
+
from arcade_google_slides.who_am_i_util import build_who_am_i_response
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@tool(
|
|
11
|
+
requires_auth=Google(
|
|
12
|
+
scopes=[
|
|
13
|
+
"https://www.googleapis.com/auth/drive.file",
|
|
14
|
+
"https://www.googleapis.com/auth/userinfo.profile",
|
|
15
|
+
"https://www.googleapis.com/auth/userinfo.email",
|
|
16
|
+
]
|
|
17
|
+
)
|
|
18
|
+
)
|
|
19
|
+
async def who_am_i(
|
|
20
|
+
context: ToolContext,
|
|
21
|
+
) -> Annotated[
|
|
22
|
+
dict[str, Any],
|
|
23
|
+
"Get comprehensive user profile and Google Slides environment information.",
|
|
24
|
+
]:
|
|
25
|
+
"""
|
|
26
|
+
Get comprehensive user profile and Google Slides environment information.
|
|
27
|
+
|
|
28
|
+
This tool provides detailed information about the authenticated user including
|
|
29
|
+
their name, email, profile picture, Google Slides access permissions, and other
|
|
30
|
+
important profile details from Google services.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
auth_token = context.get_auth_token_or_empty()
|
|
34
|
+
slides_service = build_slides_service(auth_token)
|
|
35
|
+
user_info = build_who_am_i_response(context, slides_service)
|
|
36
|
+
|
|
37
|
+
return dict(user_info)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from typing import Any, TypedDict, cast
|
|
2
|
+
|
|
3
|
+
from google.oauth2.credentials import Credentials
|
|
4
|
+
from googleapiclient.discovery import build
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WhoAmIResponse(TypedDict, total=False):
|
|
8
|
+
my_email_address: str
|
|
9
|
+
display_name: str
|
|
10
|
+
given_name: str
|
|
11
|
+
family_name: str
|
|
12
|
+
formatted_name: str
|
|
13
|
+
profile_picture_url: str
|
|
14
|
+
google_slides_access: bool
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def build_who_am_i_response(context: Any, slides_service: Any) -> WhoAmIResponse:
|
|
18
|
+
"""Build complete who_am_i response from Google Slides and People APIs."""
|
|
19
|
+
credentials = Credentials(
|
|
20
|
+
context.authorization.token if context.authorization and context.authorization.token else ""
|
|
21
|
+
)
|
|
22
|
+
people_service = _build_people_service(credentials)
|
|
23
|
+
person = _get_people_api_data(people_service)
|
|
24
|
+
|
|
25
|
+
user_info = _extract_profile_data(person)
|
|
26
|
+
user_info.update(_extract_google_slides_info(slides_service))
|
|
27
|
+
|
|
28
|
+
return cast(WhoAmIResponse, user_info)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _extract_profile_data(person: dict[str, Any]) -> dict[str, Any]:
|
|
32
|
+
"""Extract user profile data from People API response."""
|
|
33
|
+
profile_data = {}
|
|
34
|
+
|
|
35
|
+
names = person.get("names", [])
|
|
36
|
+
if names:
|
|
37
|
+
primary_name = names[0]
|
|
38
|
+
profile_data.update({
|
|
39
|
+
"display_name": primary_name.get("displayName"),
|
|
40
|
+
"given_name": primary_name.get("givenName"),
|
|
41
|
+
"family_name": primary_name.get("familyName"),
|
|
42
|
+
"formatted_name": primary_name.get("displayNameLastFirst"),
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
photos = person.get("photos", [])
|
|
46
|
+
if photos:
|
|
47
|
+
profile_data["profile_picture_url"] = photos[0].get("url")
|
|
48
|
+
|
|
49
|
+
email_addresses = person.get("emailAddresses", [])
|
|
50
|
+
if email_addresses:
|
|
51
|
+
primary_emails = [
|
|
52
|
+
email for email in email_addresses if email.get("metadata", {}).get("primary")
|
|
53
|
+
]
|
|
54
|
+
if primary_emails:
|
|
55
|
+
profile_data["my_email_address"] = primary_emails[0].get("value")
|
|
56
|
+
|
|
57
|
+
return profile_data
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _extract_google_slides_info(slides_service: Any) -> dict[str, Any]:
|
|
61
|
+
"""Extract minimal Google Slides access information."""
|
|
62
|
+
slides_info: dict[str, Any] = {}
|
|
63
|
+
try:
|
|
64
|
+
slides_info["google_slides_access"] = True
|
|
65
|
+
except Exception:
|
|
66
|
+
slides_info["google_slides_access"] = False
|
|
67
|
+
return slides_info
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _build_people_service(credentials: Credentials) -> Any:
|
|
71
|
+
"""Build and return the People API service client."""
|
|
72
|
+
return build("people", "v1", credentials=credentials)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _get_people_api_data(people_service: Any) -> dict[str, Any]:
|
|
76
|
+
"""Get user profile information from People API."""
|
|
77
|
+
person_fields = "names,emailAddresses,photos"
|
|
78
|
+
return cast(
|
|
79
|
+
dict[str, Any],
|
|
80
|
+
people_service.people().get(resourceName="people/me", personFields=person_fields).execute(),
|
|
81
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
arcade_google_slides/__init__.py,sha256=lDbDi5794U-ao476aHyqlymoVBwJAyG938e3TXV4A0c,474
|
|
2
|
+
arcade_google_slides/converters.py,sha256=kKxTeuQX_Q4-QpZWCCKteAMAZ0o2McpaWimxg-6IxHI,9870
|
|
3
|
+
arcade_google_slides/enum.py,sha256=uRBfvSfDpbZaunuA6upPP3GvXArOW8r7k6YYPsa9X9M,5289
|
|
4
|
+
arcade_google_slides/types.py,sha256=osCGae3PXl9U_eA7zqVEA6kcju6W-npXLUlsbJZIuqc,6664
|
|
5
|
+
arcade_google_slides/utils.py,sha256=OA0B7jsD6zn3B6Mpil1uSnv9t0XBqtuOXSBbn9SQ034,5125
|
|
6
|
+
arcade_google_slides/who_am_i_util.py,sha256=qXckkm6YDe51yy4pm3pqQQy3gyhTKNavr55sJxGrYxg,2734
|
|
7
|
+
arcade_google_slides/tools/__init__.py,sha256=Ki-7TlKY8dbmrhOcYN6Yw5NHypTAHToJcZzpdxVqRhk,732
|
|
8
|
+
arcade_google_slides/tools/comment.py,sha256=SCLONR43ZXBHjLFkaNnIbWvxO3qV0tG-li8HkHi1Npk,2960
|
|
9
|
+
arcade_google_slides/tools/create.py,sha256=JbKhvZH5jbj7dFXLdUhm9mHDWYChXQZ66BSilersYMA,3955
|
|
10
|
+
arcade_google_slides/tools/file_picker.py,sha256=Dqn-hfMoTsWyHM8QCakVgHr5TKrzL_1Lj-vYHVGtOW4,2342
|
|
11
|
+
arcade_google_slides/tools/get.py,sha256=i3KKR-0ZouwLRapV87_Y4OmTL2cyXA8ACwaj3FM3ALw,1013
|
|
12
|
+
arcade_google_slides/tools/search.py,sha256=6tnLT5xRQfibrcbqdGQcowhjBxhLjaojKHVjN_274uA,4768
|
|
13
|
+
arcade_google_slides/tools/system_context.py,sha256=bP9pPgxDGAXLIsRftUVHUVpbOcex_X6y6kWvTr3eAdM,1176
|
|
14
|
+
arcade_google_slides-1.1.0.dist-info/METADATA,sha256=h_alrBCJRPmmR1_Bk2wL2smDuj6PG4stuZCnBymQu2k,1190
|
|
15
|
+
arcade_google_slides-1.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
16
|
+
arcade_google_slides-1.1.0.dist-info/licenses/LICENSE,sha256=ixeE7aL9b2B-_ZYHTY1vQcJB4NufKeo-LWwKNObGDN0,1960
|
|
17
|
+
arcade_google_slides-1.1.0.dist-info/RECORD,,
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import functools
|
|
2
|
-
from collections.abc import Callable
|
|
3
|
-
from typing import Any
|
|
4
|
-
|
|
5
|
-
from arcade_tdk import ToolContext
|
|
6
|
-
from googleapiclient.errors import HttpError
|
|
7
|
-
|
|
8
|
-
from arcade_google_slides.file_picker import generate_google_file_picker_url
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def with_filepicker_fallback(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
12
|
-
""" """
|
|
13
|
-
|
|
14
|
-
@functools.wraps(func)
|
|
15
|
-
async def async_wrapper(context: ToolContext, *args: Any, **kwargs: Any) -> Any:
|
|
16
|
-
try:
|
|
17
|
-
return await func(context, *args, **kwargs)
|
|
18
|
-
except HttpError as e:
|
|
19
|
-
if e.status_code in [403, 404]:
|
|
20
|
-
file_picker_response = generate_google_file_picker_url(context)
|
|
21
|
-
return file_picker_response
|
|
22
|
-
raise
|
|
23
|
-
|
|
24
|
-
return async_wrapper
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
optional_file_picker_instructions_template = (
|
|
2
|
-
"Ensure the user knows that they have the option to select and grant access permissions to "
|
|
3
|
-
"additional documents via the Google Drive File Picker. "
|
|
4
|
-
"The user can pick additional documents via the following link: {url}"
|
|
5
|
-
)
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
arcade_google_slides/__init__.py,sha256=NJk6XPdTtpKDTdDYxzP_rOVqTxjdfSF0yQVde1KliV0,398
|
|
2
|
-
arcade_google_slides/converters.py,sha256=kKxTeuQX_Q4-QpZWCCKteAMAZ0o2McpaWimxg-6IxHI,9870
|
|
3
|
-
arcade_google_slides/decorators.py,sha256=SQeS2_fa3UOgUgGiYuY5eugguIyRPvHVc85TSracSZY,753
|
|
4
|
-
arcade_google_slides/enum.py,sha256=uRBfvSfDpbZaunuA6upPP3GvXArOW8r7k6YYPsa9X9M,5289
|
|
5
|
-
arcade_google_slides/file_picker.py,sha256=kGfUVfH5QVlIW1sL-_gAwPokt7TwVEcPk3Vnk53GKUE,2005
|
|
6
|
-
arcade_google_slides/templates.py,sha256=pxbdMj57eV3-ImW3CixDWscpVKS94Z8nTNyTxDhUfGY,283
|
|
7
|
-
arcade_google_slides/types.py,sha256=osCGae3PXl9U_eA7zqVEA6kcju6W-npXLUlsbJZIuqc,6664
|
|
8
|
-
arcade_google_slides/utils.py,sha256=OA0B7jsD6zn3B6Mpil1uSnv9t0XBqtuOXSBbn9SQ034,5125
|
|
9
|
-
arcade_google_slides/tools/__init__.py,sha256=JMWqB_57Nul0mF6vwSJsqzHp91cimmy9cvqcgM-tacw,531
|
|
10
|
-
arcade_google_slides/tools/comment.py,sha256=SCLONR43ZXBHjLFkaNnIbWvxO3qV0tG-li8HkHi1Npk,2960
|
|
11
|
-
arcade_google_slides/tools/create.py,sha256=JbKhvZH5jbj7dFXLdUhm9mHDWYChXQZ66BSilersYMA,3955
|
|
12
|
-
arcade_google_slides/tools/get.py,sha256=ZqV8gtDJR0I7wMugholR59zCtHfT5CjiaG3kwl9XCZk,1209
|
|
13
|
-
arcade_google_slides/tools/search.py,sha256=IG75QZWwWvBvi0widULJQJdheX2XfYpkSxol5u_9tT0,5346
|
|
14
|
-
arcade_google_slides-0.1.1.dist-info/METADATA,sha256=UJBsiT22Pf8FmbuNjMt72vJfa5WbYQA-80OMDd5A2xk,1190
|
|
15
|
-
arcade_google_slides-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
16
|
-
arcade_google_slides-0.1.1.dist-info/licenses/LICENSE,sha256=ixeE7aL9b2B-_ZYHTY1vQcJB4NufKeo-LWwKNObGDN0,1960
|
|
17
|
-
arcade_google_slides-0.1.1.dist-info/RECORD,,
|
|
File without changes
|
{arcade_google_slides-0.1.1.dist-info → arcade_google_slides-1.1.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|