~cytrogen/evi-run

ref: 60ce6575f4d2cd33187309b6c2d4f61ffa44d003 evi-run/bot/utils/agent_requests.py -rw-r--r-- 7.4 KiB
60ce6575 — Bendy send_answer: dynamic budget, safe HTML splitting, pre/code fixes, HTML comments escaping; agents_: tool routing wording; cleanup (remove dead code) 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import base64, json, uuid
import os
from io import BytesIO
from typing import Optional

import aiofiles
from agents.mcp import MCPServerStdio
from aiogram import Bot
from aiogram.types import BufferedInputFile
from redis.asyncio.client import Redis
from agents import Runner, RunConfig
from dataclasses import dataclass

from bot.agents_tools.agents_ import client, create_main_agent, memory_creator_agent
from database.models import User
from database.repositories.user import UserRepository
from database.repositories.utils import UtilsRepository
from config import ADMIN_ID


@dataclass
class AnswerText:
    answer: str
    image_bytes: Optional[bytes]
    input_tokens: int
    input_tokens_image: int
    output_tokens: int
    output_tokens_image: int

@dataclass
class AnswerImage:
    answer: str
    input_tokens: int
    output_tokens: int
    image_path: str


async def return_vectors(user_id: int, user_repo: UserRepository, utils_repo: UtilsRepository):
    memory_vector = await user_repo.get_memory_vector(user_id=user_id)
    if not memory_vector:
        vector_store = await client.vector_stores.create(name=f"user_memory_{user_id}")
        await user_repo.add_memory_vector(user_id=user_id, vector_store_id=vector_store.id)
        vector_store_id = vector_store.id
    else:
        vector_store_id = memory_vector.id_vector

    knowledge_vector = await utils_repo.get_knowledge_vectore_store_id()
    if not knowledge_vector:
        vector_store = await client.vector_stores.create(name="knowledge_base")
        await utils_repo.add_knowledge_vectore_store_id(vector_store.id)
        knowledge_id = vector_store.id
    else:
        knowledge_id = knowledge_vector.id_vector

    return vector_store_id, knowledge_id


async def encode_image(image_path):
    async with aiofiles.open(image_path, "rb") as image_file:
        return base64.b64encode(await image_file.read()).decode("utf-8")


async def text_request(text: str, user: User, user_repo: UserRepository, utils_repo: UtilsRepository,
                       redis: Redis, mcp_server_1: MCPServerStdio, bot: Bot, scheduler):
    vector_store_id, knowledge_id = await return_vectors(user_id=user.telegram_id, user_repo=user_repo, utils_repo=utils_repo)
    messages = await user_repo.get_messags(user_id=user.telegram_id)
    user_wallet = await user_repo.get_wallet(user_id=user.telegram_id)

    runner = await Runner.run(
        starting_agent=await create_main_agent(user_memory_id=vector_store_id, knowledge_id=knowledge_id,
                                         mcp_server_1=mcp_server_1, user_id=user.telegram_id,
                                         private_key=user_wallet),
        input=[{'role': message.role,
                'content': message.content if f'image_{user.telegram_id}' not in message.content
                else [{"type": "input_text", "text": message.content.split('|')[-1]},
                {
                    "type": "input_image",
                    "image_url": f"data:image/jpeg;base64,{await encode_image(message.content.split('|')[0])}",
                }]}
               for message in messages] + [{'role': 'user', 'content': text}],

        context=(client, user.telegram_id, user_repo, scheduler),
        run_config=RunConfig(
            tracing_disabled=False
        )
    )

    input_tokens = 0
    output_tokens = 0
    for response in runner.raw_responses:
        input_tokens += response.usage.input_tokens
        output_tokens += response.usage.output_tokens

    # await send_raw_response(bot, str(runner.raw_responses))

    answer = runner.final_output
    is_image_answer = await redis.get(f'image_{user.telegram_id}')
    if is_image_answer:
        image_answer = json.loads(is_image_answer)
        await redis.delete(f'image_{user.telegram_id}')
        image_path = image_answer['image']
        input_tokens_image = image_answer['input_tokens']
        output_tokens_image = image_answer['output_tokens']
        # await bot.send_message(chat_id=ADMIN_ID, text=f"Image Request\n\n"
        #                                               f"Input tokens: {input_tokens_image}\n"
        #                                               f"Output tokens: {output_tokens_image}\n")

        async with aiofiles.open(image_path, "rb") as image_file:
            image_bytes = await image_file.read()
        os.remove(image_path)
        return AnswerText(answer=answer, image_bytes=image_bytes, input_tokens=input_tokens,
                          input_tokens_image=input_tokens_image, output_tokens=output_tokens, output_tokens_image=output_tokens_image)

    return AnswerText(answer=answer, image_bytes=None, input_tokens=input_tokens,
                      input_tokens_image=0, output_tokens=output_tokens, output_tokens_image=0)


async def image_request(image_bytes: bytes, user: User, user_repo: UserRepository,
                        utils_repo: UtilsRepository, redis: Redis, mcp_server_1: MCPServerStdio, bot: Bot,
                        scheduler, caption: str = None):

    vector_store_id, knowledge_id = await return_vectors(user_id=user.telegram_id, user_repo=user_repo, utils_repo=utils_repo)
    messages = await user_repo.get_messags(user_id=user.telegram_id)
    user_wallet = await user_repo.get_wallet(user_id=user.telegram_id)

    id_image = uuid.uuid4()
    async with aiofiles.open(f"images/image_{user.telegram_id}_{id_image}.jpeg", "wb") as image_file:
        await image_file.write(image_bytes)

    runner = await Runner.run(
        starting_agent=await create_main_agent(user_memory_id=vector_store_id, knowledge_id=knowledge_id,
                                         mcp_server_1=mcp_server_1, user_id=user.telegram_id,
                                         private_key=user_wallet),
        input=[{'role': message.role,
                'content': message.content if f'image_{user.telegram_id}' not in message.content
                else [{"type": "input_text", "text": message.content.split('|')[-1]},
                      {
                          "type": "input_image",
                          "image_url": f"data:image/jpeg;base64,{await encode_image(message.content.split('|')[0])}",
                      }]}
               for message in messages] + [{'role': 'user', 'content': [{"type": "input_text",
                                                                         "text": f"{caption if caption else '.'}"},
                      {
                          "type": "input_image",
                          "image_url": f"data:image/jpeg;base64,{base64.b64encode(image_bytes).decode('utf-8')}",
                      }]}],

        context=(client, user.telegram_id, user_repo, scheduler),
        run_config=RunConfig(
            tracing_disabled=False
        )
    )

    # await send_raw_response(bot, str(runner.raw_responses))

    input_tokens = 0
    output_tokens = 0
    for response in runner.raw_responses:
        input_tokens += response.usage.input_tokens
        output_tokens += response.usage.output_tokens

    answer = runner.final_output

    return AnswerImage(answer=answer, input_tokens=input_tokens,
                       output_tokens=output_tokens, image_path=f'images/image_{user.telegram_id}_{id_image}.jpeg')


async def send_raw_response(bot: Bot, raw_response: str):
    bio = BytesIO()
    bio.write(raw_response.encode("utf-8"))
    bio.seek(0)

    await bot.send_document(
        chat_id=ADMIN_ID,
        document=BufferedInputFile(bio.read(), filename='raw_response.txt')
    )
    bio.close()