@@ -1522,6 +1522,78 @@ async def generate_openai_chat_completion(
15221522 )
15231523
15241524
1525+ @router .post ('/v1/messages' )
1526+ @router .post ('/v1/messages/{url_idx}' )
1527+ async def generate_anthropic_messages (
1528+ request : Request ,
1529+ form_data : dict ,
1530+ url_idx : Optional [int ] = None ,
1531+ user = Depends (get_verified_user ),
1532+ ):
1533+ """
1534+ Proxy for Ollama's Anthropic-compatible /v1/messages endpoint.
1535+
1536+ Forwards the request as-is to the Ollama backend, applying the same
1537+ model resolution, access control, and prefix_id handling used by
1538+ the OpenAI-compatible /v1/chat/completions proxy.
1539+
1540+ See https://docs.ollama.com/api/anthropic-compatibility
1541+ """
1542+ if not request .app .state .config .ENABLE_OLLAMA_API :
1543+ raise HTTPException (status_code = 503 , detail = 'Ollama API is disabled' )
1544+
1545+ payload = {** form_data }
1546+ model_id = payload .get ('model' , '' )
1547+
1548+ model_info = Models .get_model_by_id (model_id )
1549+ if model_info :
1550+ if model_info .base_model_id :
1551+ payload ['model' ] = model_info .base_model_id
1552+
1553+ # Check if user has access to the model
1554+ if user .role == 'user' :
1555+ user_group_ids = {group .id for group in Groups .get_groups_by_member_id (user .id )}
1556+ if not (
1557+ user .id == model_info .user_id
1558+ or AccessGrants .has_access (
1559+ user_id = user .id ,
1560+ resource_type = 'model' ,
1561+ resource_id = model_info .id ,
1562+ permission = 'read' ,
1563+ user_group_ids = user_group_ids ,
1564+ )
1565+ ):
1566+ raise HTTPException (
1567+ status_code = 403 ,
1568+ detail = 'Model not found' ,
1569+ )
1570+ else :
1571+ if user .role != 'admin' :
1572+ raise HTTPException (
1573+ status_code = 403 ,
1574+ detail = 'Model not found' ,
1575+ )
1576+
1577+ url , url_idx = await get_ollama_url (request , payload ['model' ], url_idx )
1578+ api_config = request .app .state .config .OLLAMA_API_CONFIGS .get (
1579+ str (url_idx ),
1580+ request .app .state .config .OLLAMA_API_CONFIGS .get (url , {}), # Legacy support
1581+ )
1582+
1583+ prefix_id = api_config .get ('prefix_id' , None )
1584+ if prefix_id :
1585+ payload ['model' ] = payload ['model' ].replace (f'{ prefix_id } .' , '' )
1586+
1587+ return await send_post_request (
1588+ url = f'{ url } /v1/messages' ,
1589+ payload = json .dumps (payload ),
1590+ stream = payload .get ('stream' , False ),
1591+ content_type = 'text/event-stream' if payload .get ('stream' , False ) else None ,
1592+ key = get_api_key (url_idx , url , request .app .state .config .OLLAMA_API_CONFIGS ),
1593+ user = user ,
1594+ )
1595+
1596+
15251597@router .get ('/v1/models' )
15261598@router .get ('/v1/models/{url_idx}' )
15271599async def get_openai_models (
0 commit comments