1- from typing import Optional , List , Tuple
2- from sqlmodel import Session , select , and_
1+ import logging
2+
3+ from typing import Optional
4+
5+ import openai
6+ from fastapi import HTTPException
7+ from openai import OpenAI
8+ from openai .types .beta import Assistant as OpenAIAssistant
9+ from sqlmodel import Session , and_ , select
310
4- from app .core .util import now
511from app .models import Assistant
12+ from app .utils import mask_string
13+
14+ logger = logging .getLogger (__name__ )
615
716
817def get_assistant_by_id (
@@ -16,3 +25,89 @@ def get_assistant_by_id(
1625 )
1726 )
1827 return session .exec (statement ).first ()
28+
29+
30+ def fetch_assistant_from_openai (assistant_id : str , client : OpenAI ) -> OpenAIAssistant :
31+ """
32+ Fetch an assistant from OpenAI.
33+ Returns OpenAI Assistant model.
34+ """
35+
36+ try :
37+ assistant = client .beta .assistants .retrieve (assistant_id = assistant_id )
38+ return assistant
39+ except openai .NotFoundError as e :
40+ logger .error (
41+ f"[fetch_assistant_from_openai] Assistant not found: { mask_string (assistant_id )} | { e } "
42+ )
43+ raise HTTPException (status_code = 404 , detail = "Assistant not found in OpenAI." )
44+ except openai .OpenAIError as e :
45+ logger .error (
46+ f"[fetch_assistant_from_openai] OpenAI API error while retrieving assistant { mask_string (assistant_id )} : { e } "
47+ )
48+ raise HTTPException (status_code = 502 , detail = f"OpenAI API error: { e } " )
49+
50+
51+ def sync_assistant (
52+ session : Session ,
53+ organization_id : int ,
54+ project_id : int ,
55+ openai_assistant : OpenAIAssistant ,
56+ ) -> Assistant :
57+ """
58+ Insert an assistant into the database by converting OpenAI Assistant to local Assistant model.
59+ """
60+ assistant_id = openai_assistant .id
61+
62+ existing_assistant = get_assistant_by_id (session , assistant_id , organization_id )
63+ if existing_assistant :
64+ logger .info (
65+ f"[sync_assistant] Assistant with ID { mask_string (assistant_id )} already exists in the database."
66+ )
67+ raise HTTPException (
68+ status_code = 409 ,
69+ detail = f"Assistant with ID { assistant_id } already exists." ,
70+ )
71+
72+ if not openai_assistant .instructions :
73+ raise HTTPException (
74+ status_code = 400 ,
75+ detail = "Assistant has no instruction." ,
76+ )
77+
78+ vector_store_ids = []
79+ if openai_assistant .tool_resources and hasattr (
80+ openai_assistant .tool_resources , "file_search"
81+ ):
82+ file_search = openai_assistant .tool_resources .file_search
83+ if file_search and hasattr (file_search , "vector_store_ids" ):
84+ vector_store_ids = file_search .vector_store_ids or []
85+
86+ max_num_results = 20
87+ for tool in openai_assistant .tools or []:
88+ if tool .type == "file_search" :
89+ file_search = getattr (tool , "file_search" , None )
90+ if file_search and hasattr (file_search , "max_num_results" ):
91+ max_num_results = file_search .max_num_results
92+ break
93+
94+ db_assistant = Assistant (
95+ assistant_id = openai_assistant .id ,
96+ name = openai_assistant .name or openai_assistant .id ,
97+ instructions = openai_assistant .instructions ,
98+ model = openai_assistant .model ,
99+ vector_store_ids = vector_store_ids ,
100+ temperature = openai_assistant .temperature or 0.1 ,
101+ max_num_results = max_num_results ,
102+ project_id = project_id ,
103+ organization_id = organization_id ,
104+ )
105+
106+ session .add (db_assistant )
107+ session .commit ()
108+ session .refresh (db_assistant )
109+
110+ logger .info (
111+ f"[sync_assistant] Successfully ingested assistant with ID { mask_string (assistant_id )} ."
112+ )
113+ return db_assistant
0 commit comments