Skip to content

Commit

Permalink
yc fc api
Browse files Browse the repository at this point in the history
  • Loading branch information
all-mute committed Nov 28, 2024
1 parent 3ab7f37 commit e0b88a4
Show file tree
Hide file tree
Showing 21 changed files with 852 additions and 92 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/yc_fc_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Weekly Notebook Test (YC FC)

on:
schedule:
- cron: '0 0 * * 4' # Запуск каждое четверг в 00:00 UTC
push:
branches:
- main
pull_request:
branches:
- main

jobs:
test-notebook:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'

- name: Create .env file
run: |
echo "FOLDER_ID=${{ secrets.FOLDER_ID }}" >> .env
echo "YANDEX_API_KEY=${{ secrets.YANDEX_API_KEY }}" >> .env
echo "PROXY_URL=${{ secrets.PROXY_URL }}" >> .env
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r yc/function_calling_api/requirements.txt
pip install jupyter nbconvert
- name: Execute notebook
run: |
jupyter nbconvert --to notebook --execute yc/function_calling_api/lesson.ipynb --output executed_notebook.ipynb
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.env
__pycache__
.venv
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# В этом репозитории собраны руководства по AIOps, LLMSysDesign и LLM-проектам
для сайта https://ai-cookbook.ru

Список руководств:
- [YC function calling по API](yc/function_calling_api/lesson.ipynb)
- [YC function calling через OpenAI SDK](yc/function_calling_openai/lesson.ipynb)
- [YC function calling через YC ML SDK](yc/function_calling_ml_sdk/lesson.ipynb)

Для работы с любым гайдом (пример для yc/function_calling_api):

# Start of Selection
1. `cd yc/function_calling_api`
2. `cp .env .env.copy`, заполнить своими данными
3. `pip install -r requirements.txt`
13 changes: 0 additions & 13 deletions cloud_instruments/sf.py

This file was deleted.

Empty file removed fc_guide.py
Empty file.
Empty file removed fc_sqlite.py
Empty file.
25 changes: 0 additions & 25 deletions func_calling.py

This file was deleted.

16 changes: 0 additions & 16 deletions output.md

This file was deleted.

8 changes: 8 additions & 0 deletions yc/function_calling_api/.env.copy
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FOLDER_ID=
YANDEX_API_KEY=

# Search API
#SERP_SITE=https://yandex.cloud/ru/docs
SERP_SITE=
SERP_HOST=
SERP_URL=
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
dotenv.load_dotenv()

# Получение идентификаторов папки и API ключа
FOLDER_ID = os.getenv('YC_FOLDER_ID')
API_KEY = os.getenv('YC_API_KEY')
FOLDER_ID = os.getenv('FOLDER_ID')
API_KEY = os.getenv('YANDEX_API_KEY')

# URL для генеративного поиска
SEARCH_API_GENERATIVE = f"https://ya.ru/search/xml/generative?folderid={FOLDER_ID}"
Expand All @@ -29,46 +29,16 @@ def process_response(response):
if "application/json" in response.headers.get("Content-Type", ""):
content = response.json().get("message", {}).get("content", "")
sources = response.json().get("links", [])
logger.info(content)
for i, link in enumerate(sources, start=1):
logger.info(f"[{i}]: {link}")
elif "text/xml" in response.headers.get("Content-Type", ""):
logger.error(f"Ошибка: {response.text}")
pass # Ошибка не логируется
else:
logger.error(f"Неожиданный тип контента: {response.text}")
pass # Неожиданный тип контента не логируется

# Формируем комбинированный контент для ответа
combined_content = f"Ответ SearchAPI:\n{content}\n\nИсточники:\n" + "\n".join(sources)
return combined_content

async def search_api_generative_contextual(message: str, thread_id: str):
"""Выполняет генеративный поиск с учетом контекста треда."""
# Получаем сообщения из треда
thread_messages = sdk.threads.get(thread_id).read()
messages = [{"content": item.parts[0], "role": item.role} for item in thread_messages]

# Добавляем новое сообщение от пользователя
messages.append({"content": message, "role": "user"})

headers = {"Authorization": f"Api-Key {API_KEY}"}
data = {
"messages": messages,
"site": SERP_SITE,
"host": SERP_HOST,
"url": SERP_URL
}

# Отправляем запрос к API
response = requests.post(SEARCH_API_GENERATIVE, headers=headers, json=data)
combined_content = process_response(response)

# Записываем сообщения в тред
thread = sdk.threads.get(thread_id)
thread.write(message)
thread.write(combined_content, labels={"role": "assistant"})
return combined_content

async def search_api_generative(message: str):
def search_api_generative(message: str) -> str:
"""Выполняет генеративный поиск без контекста треда."""
headers = {"Authorization": f"Api-Key {API_KEY}"}
data = {
Expand Down
13 changes: 13 additions & 0 deletions yc/function_calling_api/cloud_instruments/serverless_func.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import httpx

def send_post_request(name):
url = f"https://functions.yandexcloud.net/d4ekuoccv9lmm79dh5rr?name={name}"
with httpx.Client() as client:
response = client.get(url)
# print(f"Status Code: {response.status_code}")
# print(f"Response Content: {response.text}")
return response.text

if __name__ == "__main__":
name = "Master"
send_post_request(name)
File renamed without changes.
File renamed without changes.
File renamed without changes.
18 changes: 15 additions & 3 deletions fc_utils.py → yc/function_calling_api/fc_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import os
import sqlite3
from termcolor import colored
from cloud_instruments.searchapi import search_api_generative
from cloud_instruments.serverless_func import send_post_request

GPT_MODEL = "yandexgpt/rc"
FOLDER_ID = os.getenv('FOLDER_ID') or ''
Expand Down Expand Up @@ -72,7 +74,8 @@ def pack_function_result(name: str, content: str):
}

def process_tool_product_list_tool(category: str, priceMinMax: list[int], sortBy: str = 'price') -> list[dict]:
return [{'productId': 'siaomi453', 'name': 'сяоми 4+ pro', 'category': category, 'price': priceMinMax[1]}]
return [{'productId': 'siaomi453', 'name': 'сяоми 4+ pro', 'category': category, 'price': 10_000},
{'productId': 'iphone15', 'name': 'iphone 15', 'category': category, 'price': 280_000}]

def process_tool_balance_tool(userId: str) -> dict:
# Обработка аргументов: userId
Expand All @@ -90,12 +93,21 @@ def process_tool_sql_tool(query: str) -> str:
conn.close()
return result

def process_tool_searchapi(query: str) -> str:
return search_api_generative(query)

def process_tool_serverless_func(name: str) -> str:
return send_post_request(name)


def process_functions(toolCalls):
tools_map = {
"ProductListTool": process_tool_product_list_tool,
"BalanceTool": process_tool_balance_tool,
"OrderTool": process_tool_order_tool,
"ask_database": process_tool_sql_tool
"ask_database": process_tool_sql_tool,
"searchapi": process_tool_searchapi,
"serverless_func": process_tool_serverless_func
}

results = []
Expand Down Expand Up @@ -131,7 +143,7 @@ def pretty_print_conversation(messages):

if __name__ == '__main__':
test_messages = [
{"role": "system", "text": "Ты - полезный бот, который помогает пользователю с его проблемами. Ты можешь использовать инструменты, чтобы получить актуальную информацию. Но пользоваться ими нужно не всегда. "},
{"role": "system", "text": "Ты - полезный бот, который помогает пользователю с его проблемами. Ты можешь использовать инструменты, чтобы получить актуальную информацию. Но пользоваться ими нужно не всегда."},
{"role": "user", "text": "Сколько у меня денег на балансе?"}
]

Expand Down
Loading

0 comments on commit e0b88a4

Please sign in to comment.