Spaces:
Sleeping
Sleeping
update
Browse files- app.py +131 -3
- local_config.json +0 -23
- requirements.txt +2 -1
app.py
CHANGED
|
@@ -32,6 +32,7 @@ from googleapiclient.http import MediaIoBaseUpload
|
|
| 32 |
from educational_material import EducationalMaterial
|
| 33 |
from storage_service import GoogleCloudStorage
|
| 34 |
|
|
|
|
| 35 |
|
| 36 |
is_env_local = os.getenv("IS_ENV_LOCAL", "false") == "true"
|
| 37 |
print(f"is_env_local: {is_env_local}")
|
|
@@ -45,6 +46,9 @@ if is_env_local:
|
|
| 45 |
OPEN_AI_KEY = config["OPEN_AI_KEY"]
|
| 46 |
GROQ_API_KEY = config["GROQ_API_KEY"]
|
| 47 |
JUTOR_CHAT_KEY = config["JUTOR_CHAT_KEY"]
|
|
|
|
|
|
|
|
|
|
| 48 |
OUTPUT_PATH = config["OUTPUT_PATH"]
|
| 49 |
else:
|
| 50 |
PASSWORD = os.getenv("PASSWORD")
|
|
@@ -53,6 +57,9 @@ else:
|
|
| 53 |
OPEN_AI_KEY = os.getenv("OPEN_AI_KEY")
|
| 54 |
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
|
| 55 |
JUTOR_CHAT_KEY = os.getenv("JUTOR_CHAT_KEY")
|
|
|
|
|
|
|
|
|
|
| 56 |
OUTPUT_PATH = 'videos'
|
| 57 |
|
| 58 |
TRANSCRIPTS = []
|
|
@@ -64,6 +71,20 @@ GROQ_CLIENT = Groq(api_key=GROQ_API_KEY)
|
|
| 64 |
GCS_SERVICE = GoogleCloudStorage(GCS_KEY)
|
| 65 |
GCS_CLIENT = GCS_SERVICE.client
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
# 驗證 password
|
| 68 |
def verify_password(password):
|
| 69 |
if password == PASSWORD:
|
|
@@ -1615,6 +1636,106 @@ def poll_run_status(run_id, thread_id, timeout=600, poll_interval=5):
|
|
| 1615 |
|
| 1616 |
return run.status
|
| 1617 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1618 |
def update_slide(direction):
|
| 1619 |
global TRANSCRIPTS
|
| 1620 |
global CURRENT_INDEX
|
|
@@ -1743,7 +1864,6 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
|
|
| 1743 |
mind_map_html = gr.HTML()
|
| 1744 |
with gr.Column(scale=2):
|
| 1745 |
with gr.Tab("OPENAI"):
|
| 1746 |
-
gr.Markdown("## OPEN AI 模式")
|
| 1747 |
bot_avatar = "https://junyi-avatar.s3.ap-northeast-1.amazonaws.com/live/%20%20foxcat-star-18.png?v=20231113095823614"
|
| 1748 |
user_avatar = "https://junyitopicimg.s3.amazonaws.com/s4byy--icon.jpe?v=20200513013523726"
|
| 1749 |
chatbot = gr.Chatbot(avatar_images=[bot_avatar, user_avatar], label="OPEN AI", show_share_button=False, likeable=True)
|
|
@@ -1753,15 +1873,17 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
|
|
| 1753 |
msg = gr.Textbox(label="Message")
|
| 1754 |
send_button = gr.Button("Send", variant="primary")
|
| 1755 |
with gr.Tab("GROQ"):
|
| 1756 |
-
gr.Markdown("## GROQ 模式")
|
| 1757 |
groq_chatbot = gr.Chatbot(avatar_images=[bot_avatar, user_avatar], label="groq mode chatbot", show_share_button=False)
|
| 1758 |
groq_msg = gr.Textbox(label="Message")
|
| 1759 |
groq_send_button = gr.Button("Send", variant="primary")
|
| 1760 |
with gr.Tab("JUTOR"):
|
| 1761 |
-
gr.Markdown("## JUTOR API 模式")
|
| 1762 |
jutor_chatbot = gr.Chatbot(avatar_images=[bot_avatar, user_avatar], label="jutor mode chatbot", show_share_button=False)
|
| 1763 |
jutor_msg = gr.Textbox(label="Message")
|
| 1764 |
jutor_send_button = gr.Button("Send", variant="primary")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1765 |
|
| 1766 |
with gr.Tab("教師版"):
|
| 1767 |
with gr.Row():
|
|
@@ -1873,6 +1995,12 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
|
|
| 1873 |
inputs=[password, jutor_msg, df_string_output, jutor_chatbot, socratic_mode_btn],
|
| 1874 |
outputs=[jutor_msg, jutor_chatbot]
|
| 1875 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1876 |
|
| 1877 |
# 连接按钮点击事件
|
| 1878 |
chat_with_opan_ai_assistant_input =[password, video_id, thread_id, df_string_output, btn_1, chatbot, content_subject, content_grade, socratic_mode_btn]
|
|
|
|
| 32 |
from educational_material import EducationalMaterial
|
| 33 |
from storage_service import GoogleCloudStorage
|
| 34 |
|
| 35 |
+
import boto3
|
| 36 |
|
| 37 |
is_env_local = os.getenv("IS_ENV_LOCAL", "false") == "true"
|
| 38 |
print(f"is_env_local: {is_env_local}")
|
|
|
|
| 46 |
OPEN_AI_KEY = config["OPEN_AI_KEY"]
|
| 47 |
GROQ_API_KEY = config["GROQ_API_KEY"]
|
| 48 |
JUTOR_CHAT_KEY = config["JUTOR_CHAT_KEY"]
|
| 49 |
+
AWS_ACCESS_KEY = config["AWS_ACCESS_KEY"]
|
| 50 |
+
AWS_SECRET_KEY = config["AWS_SECRET_KEY"]
|
| 51 |
+
AWS_REGION_NAME = config["AWS_REGION_NAME"]
|
| 52 |
OUTPUT_PATH = config["OUTPUT_PATH"]
|
| 53 |
else:
|
| 54 |
PASSWORD = os.getenv("PASSWORD")
|
|
|
|
| 57 |
OPEN_AI_KEY = os.getenv("OPEN_AI_KEY")
|
| 58 |
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
|
| 59 |
JUTOR_CHAT_KEY = os.getenv("JUTOR_CHAT_KEY")
|
| 60 |
+
AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY"),
|
| 61 |
+
AWS_SECRET_KEY = os.getenv("AWS_SECRET_KEY"),
|
| 62 |
+
AWS_REGION_NAME = 'us-west-2'
|
| 63 |
OUTPUT_PATH = 'videos'
|
| 64 |
|
| 65 |
TRANSCRIPTS = []
|
|
|
|
| 71 |
GCS_SERVICE = GoogleCloudStorage(GCS_KEY)
|
| 72 |
GCS_CLIENT = GCS_SERVICE.client
|
| 73 |
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
# 初始化 boto3 session
|
| 77 |
+
boto3.setup_default_session(
|
| 78 |
+
aws_access_key_id=AWS_ACCESS_KEY,
|
| 79 |
+
aws_secret_access_key=AWS_SECRET_KEY,
|
| 80 |
+
region_name=AWS_REGION_NAME
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
BEDROCK_CLIENT = boto3.client(
|
| 84 |
+
service_name="bedrock-runtime",
|
| 85 |
+
region_name=AWS_REGION_NAME
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
# 驗證 password
|
| 89 |
def verify_password(password):
|
| 90 |
if password == PASSWORD:
|
|
|
|
| 1636 |
|
| 1637 |
return run.status
|
| 1638 |
|
| 1639 |
+
def chat_with_claude3(password, user_message, data, chat_history, socratic_mode=False):
|
| 1640 |
+
verify_password(password)
|
| 1641 |
+
data_json = json.loads(data)
|
| 1642 |
+
for entry in data_json:
|
| 1643 |
+
entry.pop('embed_url', None) # Remove 'embed_url' if it exists
|
| 1644 |
+
entry.pop('screenshot_path', None)
|
| 1645 |
+
|
| 1646 |
+
if socratic_mode:
|
| 1647 |
+
sys_content = f"""
|
| 1648 |
+
你是一個擅長資料分析跟影片教學的老師,user 為學生
|
| 1649 |
+
請用 {data} 為資料文本,自行判斷資料的種類,
|
| 1650 |
+
並進行對話,使用 台灣人的口與表達,及繁體中文zh-TW
|
| 1651 |
+
請你用蘇格拉底式的提問方式,引導學生思考,並且給予學生一些提示
|
| 1652 |
+
不要直接給予答案,讓學生自己思考
|
| 1653 |
+
但可以給予一些提示跟引導,例如給予影片的時間軸,讓學生自己去找答案
|
| 1654 |
+
|
| 1655 |
+
如果學生問了一些問題你無法判斷,請告訴學生你無法判斷,並建議學生可以問其他問題
|
| 1656 |
+
或者你可以問學生一些問題,幫助學生更好的理解資料
|
| 1657 |
+
|
| 1658 |
+
如果學生的問題與資料文本無關,請告訴學生你無法回答超出範圍的問題
|
| 1659 |
+
|
| 1660 |
+
最後,在你回答的開頭標註【蘇格拉底助教】
|
| 1661 |
+
"""
|
| 1662 |
+
else:
|
| 1663 |
+
sys_content = f"""
|
| 1664 |
+
你是一個擅長資料分析跟影片教學的老師,user 為學生
|
| 1665 |
+
請用 {data} 為資料文本,自行判斷資料的種類,
|
| 1666 |
+
並進行對話,使用 zh-TW
|
| 1667 |
+
|
| 1668 |
+
如果是影片類型,不用解釋逐字稿格式,直接回答學生問題
|
| 1669 |
+
但可以給予一些提示跟引導,例如給予影片的時間軸,讓學生可以找到相對應的時間點
|
| 1670 |
+
|
| 1671 |
+
如果學生問了一些問題你無法判斷,請告訴學生你無法判斷,並建議學生可以問其他問題
|
| 1672 |
+
或者你可以問學生一些問題,幫助學生更好的理解資料
|
| 1673 |
+
|
| 1674 |
+
如果學生的問題與資料文本無關,請告訴學生你無法回答超出範圍的問題
|
| 1675 |
+
"""
|
| 1676 |
+
|
| 1677 |
+
messages = []
|
| 1678 |
+
|
| 1679 |
+
# if chat_history is not none, append role, content to messages
|
| 1680 |
+
# chat_history = [(user, assistant), (user, assistant), ...]
|
| 1681 |
+
# In the list, first one is user, then assistant
|
| 1682 |
+
if chat_history is not None:
|
| 1683 |
+
# 如果超過10則訊息,只保留最後10則訊息
|
| 1684 |
+
if len(chat_history) > 10:
|
| 1685 |
+
chat_history = chat_history[-10:]
|
| 1686 |
+
|
| 1687 |
+
for chat in chat_history:
|
| 1688 |
+
old_messages = [
|
| 1689 |
+
{"role": "user", "content": chat[0]},
|
| 1690 |
+
{"role": "assistant", "content": chat[1]}
|
| 1691 |
+
]
|
| 1692 |
+
messages += old_messages
|
| 1693 |
+
else:
|
| 1694 |
+
pass
|
| 1695 |
+
|
| 1696 |
+
messages.append({"role": "user", "content": user_message})
|
| 1697 |
+
model_id = "anthropic.claude-3-sonnet-20240229-v1:0"
|
| 1698 |
+
# model_id = "anthropic.claude-3-haiku-20240307-v1:0"
|
| 1699 |
+
kwargs = {
|
| 1700 |
+
"modelId": model_id,
|
| 1701 |
+
"contentType": "application/json",
|
| 1702 |
+
"accept": "application/json",
|
| 1703 |
+
"body": json.dumps({
|
| 1704 |
+
"anthropic_version": "bedrock-2023-05-31",
|
| 1705 |
+
"max_tokens": 1000,
|
| 1706 |
+
"system": sys_content,
|
| 1707 |
+
"messages": messages
|
| 1708 |
+
})
|
| 1709 |
+
}
|
| 1710 |
+
# 建立 message API,讀取回應
|
| 1711 |
+
response = BEDROCK_CLIENT.invoke_model(**kwargs)
|
| 1712 |
+
|
| 1713 |
+
if response:
|
| 1714 |
+
# 处理响应数据
|
| 1715 |
+
response_body = json.loads(response.get('body').read())
|
| 1716 |
+
response_completion = response_body.get('content')[0].get('text').strip()
|
| 1717 |
+
# 更新聊天历史
|
| 1718 |
+
new_chat_history = (user_message, response_completion)
|
| 1719 |
+
if chat_history is None:
|
| 1720 |
+
chat_history = [new_chat_history]
|
| 1721 |
+
else:
|
| 1722 |
+
chat_history.append(new_chat_history)
|
| 1723 |
+
|
| 1724 |
+
# 返回聊天历史和空字符串清空输入框
|
| 1725 |
+
return "", chat_history
|
| 1726 |
+
else:
|
| 1727 |
+
# 处理错误情况
|
| 1728 |
+
print(f"Error: {response.status_code}")
|
| 1729 |
+
return "请求失败,请稍后再试!", chat_history
|
| 1730 |
+
|
| 1731 |
+
|
| 1732 |
+
|
| 1733 |
+
|
| 1734 |
+
|
| 1735 |
+
|
| 1736 |
+
|
| 1737 |
+
|
| 1738 |
+
|
| 1739 |
def update_slide(direction):
|
| 1740 |
global TRANSCRIPTS
|
| 1741 |
global CURRENT_INDEX
|
|
|
|
| 1864 |
mind_map_html = gr.HTML()
|
| 1865 |
with gr.Column(scale=2):
|
| 1866 |
with gr.Tab("OPENAI"):
|
|
|
|
| 1867 |
bot_avatar = "https://junyi-avatar.s3.ap-northeast-1.amazonaws.com/live/%20%20foxcat-star-18.png?v=20231113095823614"
|
| 1868 |
user_avatar = "https://junyitopicimg.s3.amazonaws.com/s4byy--icon.jpe?v=20200513013523726"
|
| 1869 |
chatbot = gr.Chatbot(avatar_images=[bot_avatar, user_avatar], label="OPEN AI", show_share_button=False, likeable=True)
|
|
|
|
| 1873 |
msg = gr.Textbox(label="Message")
|
| 1874 |
send_button = gr.Button("Send", variant="primary")
|
| 1875 |
with gr.Tab("GROQ"):
|
|
|
|
| 1876 |
groq_chatbot = gr.Chatbot(avatar_images=[bot_avatar, user_avatar], label="groq mode chatbot", show_share_button=False)
|
| 1877 |
groq_msg = gr.Textbox(label="Message")
|
| 1878 |
groq_send_button = gr.Button("Send", variant="primary")
|
| 1879 |
with gr.Tab("JUTOR"):
|
|
|
|
| 1880 |
jutor_chatbot = gr.Chatbot(avatar_images=[bot_avatar, user_avatar], label="jutor mode chatbot", show_share_button=False)
|
| 1881 |
jutor_msg = gr.Textbox(label="Message")
|
| 1882 |
jutor_send_button = gr.Button("Send", variant="primary")
|
| 1883 |
+
with gr.Tab("CLAUDE"):
|
| 1884 |
+
claude_chatbot = gr.Chatbot(avatar_images=[bot_avatar, user_avatar], label="claude mode chatbot", show_share_button=False)
|
| 1885 |
+
claude_msg = gr.Textbox(label="Message")
|
| 1886 |
+
claude_send_button = gr.Button("Send", variant="primary")
|
| 1887 |
|
| 1888 |
with gr.Tab("教師版"):
|
| 1889 |
with gr.Row():
|
|
|
|
| 1995 |
inputs=[password, jutor_msg, df_string_output, jutor_chatbot, socratic_mode_btn],
|
| 1996 |
outputs=[jutor_msg, jutor_chatbot]
|
| 1997 |
)
|
| 1998 |
+
# CLAUDE 模式
|
| 1999 |
+
claude_send_button.click(
|
| 2000 |
+
chat_with_claude3,
|
| 2001 |
+
inputs=[password, claude_msg, df_string_output, claude_chatbot, socratic_mode_btn],
|
| 2002 |
+
outputs=[claude_msg, claude_chatbot]
|
| 2003 |
+
)
|
| 2004 |
|
| 2005 |
# 连接按钮点击事件
|
| 2006 |
chat_with_opan_ai_assistant_input =[password, video_id, thread_id, df_string_output, btn_1, chatbot, content_subject, content_grade, socratic_mode_btn]
|
local_config.json
DELETED
|
@@ -1,23 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"OUTPUT_PATH": "/Users/young/Downloads",
|
| 3 |
-
"TRANSCRIPTS": [],
|
| 4 |
-
"CURRENT_INDEX": 0,
|
| 5 |
-
"VIDEO_ID": "",
|
| 6 |
-
"PASSWORD": "6161",
|
| 7 |
-
"OPEN_AI_KEY": "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",
|
| 8 |
-
"GROQ_API_KEY": "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",
|
| 9 |
-
"JUTOR_CHAT_KEY": "b4c318b8d6f770e10163436e0e868b806f50f34ae57f378e78956fb76b41fd27",
|
| 10 |
-
"GOOGLE_APPLICATION_CREDENTIALS_JSON": {
|
| 11 |
-
"type": "service_account",
|
| 12 |
-
"project_id": "junyiacademy",
|
| 13 |
-
"private_key_id": "95d4580de7518ff96be219626c58b23f1754ec6a",
|
| 14 |
-
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmo3M8Ix46FLNS\nX8NGnEMiZBomXQOEfKCRUy0khm5IKgu5RUIWSF/0UuZeWXG93a1PMarBWokTTIpo\njtRNuEAh+H8lbacJ/G6EH5PxyMjPAOROXLvSJUg4c6lOFp/WoFlnirSPsD/YHL3l\nKKm6//h/tN7GDhaqOKrf9xJ1IlSt7odhCgcR7r3dF/+pbZ2UMDA0rmNmj2aJq7rl\n1qOD/8yC3ainledRRSt8oE7t4w+3eqI5GO7OdLiNwSxGGBNx9IiJln6TFC7frvET\nzr2ZUVLL7jFdWNyfXPU3/B+7JwyXgFGfHpiyQ2xyFAUR62HkpVxs0bKNbnLLmKoL\nIXCQ+lB9AgMBAAECggEAAJLA1C/E7E46SeEqdP3o/TbAwy+Ro4dnUaRNbaK9HmJv\nXymcYJc/JfxjBcRu0qV6wyaeaH1UVZJ67TtWX6JvuPQDWQ2dVX5eovW42aks/AlR\n1wSgeA5rr7pkrZ6jZWa2XGNfOLxpwaGpIqrcx7T/ija/Qc8qmShnSyx+awi9YdX4\n/ih1Ug1fqHPQ1j3Xx23J/S4Wb6eamJZ1BW+txZUUVD2KFnw7iJWR81ceTIuoSY4R\na3Vd8yB1Ri9iVaP6pe0WeA14VfU1d3tbO0GRF6XsEtdRynVXA17nO6okc3yV0bOQ\nnWqibtfT6AWmJFIyya3DrZDxKqSFNuVfHaJrO2LvwQKBgQDRGUzCYJpGw6NAQuKw\n3egfBoTjozZxjykZb0GFFRCIIE9AmX0PkCbz9bxjjMtb9pTH3aVIiv8mL3rfqzdK\nEPEfyC5TntWqahqBW+fOMrpnU54o4Ji1TlFuSBMRBxqIPcJnKFuttkfPZiHbxe3i\nkeqBbJ4HafH5ZNAV+pHwQKSXDwKBgQDMBAbxvSKgYXxeGMOs62rK6y9NeZlKpRUJ\nORdBv+3sLTwSjlpEPwn/KgMXHaHnpDXhtTDP0ad9nLOKnZ5k8dRNcpyUEXVC2WTD\nDHd37lChG0XRnfGuxIvfr5ZYajN/sIgV8WuNpFuWnFj+mGdi+OpzS+KG3J2rMx/k\n4jl1l8g/swKBgQCYJCVyxSFb3dt51XDmKgBMGs00aLwjcnwAErCEqagGtCOWKFgT\nq9p75dA2SupotojYyBAMMX6nBSMNfaHUFXGso1X55/clcOBqQTnwEX8J0ZChw5G5\nUgv0ByNAX3/Ro8ZAkt/qDFhBstlt9J07HtqXYzW0xUSYJt81LsVjH1XixwKBgDF6\nUIzUB8/JlLXlX59SQMYRn5k0gl6+BooEFIXXnEYI+matq2qdtzjw4Wr7vsZE5uRk\nYwAjonEuTcSyUTW+CHT39M1cJood2vgKz/aAD4Hi8V3S5kgyVpHbLaUnrHGtSHO5\n5xGk6KlwJY0pPPmd0I5BuyBl5L8eWP/TdYf1VZVNAoGAUEMSVxBd/onX5LXrzkR7\nOS8w6L+YL68yWCFs1pocfY+cZfkBpteLXzqOMKN2Xc3C7TGGySnEaQlG8bF1P00E\nW9HZvrSYbhsZwEKiIxY3suWRMPRlbeHU9hxt7rYPM+kwl8zy+Z/UtE28Zwhcr0+r\n7EkfwiOEvYStw0mJ9xwhiwU=\n-----END PRIVATE KEY-----\n",
|
| 15 |
-
"client_email": "analytics-api@junyiacademy.iam.gserviceaccount.com",
|
| 16 |
-
"client_id": "113360448655635325414",
|
| 17 |
-
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
| 18 |
-
"token_uri": "https://oauth2.googleapis.com/token",
|
| 19 |
-
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
| 20 |
-
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/analytics-api%40junyiacademy.iam.gserviceaccount.com",
|
| 21 |
-
"universe_domain": "googleapis.com"
|
| 22 |
-
}
|
| 23 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
|
@@ -15,4 +15,5 @@ google-cloud-storage
|
|
| 15 |
groq
|
| 16 |
yt_dlp
|
| 17 |
uuid
|
| 18 |
-
gtts
|
|
|
|
|
|
| 15 |
groq
|
| 16 |
yt_dlp
|
| 17 |
uuid
|
| 18 |
+
gtts
|
| 19 |
+
boto3
|