Compare commits

..
Author SHA1 Message Date
Shroominic 31898192b2 added missing delete button for custom models 2026-01-29 13:05:56 +08:00
4 changed files with 52 additions and 21 deletions
+3 -1
View File
@@ -291,7 +291,9 @@ async def raw_send_to_lnurl(
lnurl_data["callback_url"], final_amount
)
melt_quote_resp = await wallet.melt_quote(invoice=bolt11_invoice)
melt_quote_resp = await wallet.melt_quote(
invoice=bolt11_invoice, amount_msat=final_amount
)
if amount:
proofs, _ = await wallet.select_to_send(proofs, amount, set_reserved=True)
+6 -19
View File
@@ -427,11 +427,7 @@ class BaseUpstreamProvider:
)
async def handle_streaming_chat_completion(
self,
response: httpx.Response,
key: ApiKey,
max_cost_for_model: int,
background_tasks: BackgroundTasks,
self, response: httpx.Response, key: ApiKey, max_cost_for_model: int
) -> StreamingResponse:
"""Handle streaming chat completion responses with token usage tracking and cost adjustment.
@@ -538,14 +534,7 @@ class BaseUpstreamProvider:
}
yield f"data: {json.dumps(usage_chunk_data)}\n\n".encode()
usage_finalized = True
except Exception as e:
logger.exception(
"Error during usage finalization",
extra={
"key_hash": key.hashed_key[:8] + "...",
"error": str(e),
},
)
except Exception:
# Fallback: yield original usage chunk if adjustment fails
yield f"data: {json.dumps(usage_chunk_data)}\n\n".encode()
@@ -566,9 +555,7 @@ class BaseUpstreamProvider:
raise
finally:
if not usage_finalized:
# Create a background task to ensure finalization happens
# even if the generator is closed early
background_tasks.add_task(finalize_db_only)
await finalize_db_only()
# Remove inaccurate encoding headers from upstream response
response_headers = dict(response.headers)
@@ -1149,12 +1136,12 @@ class BaseUpstreamProvider:
)
if is_streaming and response.status_code == 200:
result = await self.handle_streaming_chat_completion(
response, key, max_cost_for_model
)
background_tasks = BackgroundTasks()
background_tasks.add_task(response.aclose)
background_tasks.add_task(client.aclose)
result = await self.handle_streaming_chat_completion(
response, key, max_cost_for_model, background_tasks
)
result.background = background_tasks
return result
+2 -1
View File
@@ -319,7 +319,6 @@ async def periodic_payout() -> None:
wallet, mint_url, unit, not_reserved=True
)
proofs = await slow_filter_spend_proofs(proofs, wallet)
await asyncio.sleep(5)
user_balance = await db.balances_for_mint_and_unit(
session, mint_url, unit
)
@@ -345,6 +344,8 @@ async def periodic_payout() -> None:
"amount_received": amount_received,
},
)
await asyncio.sleep(5)
except Exception as e:
logger.error(
f"Error sending payout: {type(e).__name__}",
+41
View File
@@ -484,6 +484,25 @@ export default function ProvidersPage() {
},
});
const deleteModelMutation = useMutation({
mutationFn: ({
providerId,
modelId,
}: {
providerId: number;
modelId: string;
}) => AdminService.deleteProviderModel(providerId, modelId),
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: ['provider-models', variables.providerId],
});
toast.success('Model deleted successfully');
},
onError: (error: Error) => {
toast.error(`Failed to delete model: ${error.message}`);
},
});
const handleCreateAccount = async () => {
setIsCreatingAccount(true);
try {
@@ -562,6 +581,12 @@ export default function ProvidersPage() {
}
};
const handleDeleteModel = (providerId: number, modelId: string) => {
if (confirm('Are you sure you want to delete this model?')) {
deleteModelMutation.mutate({ providerId, modelId });
}
};
const getDefaultBaseUrl = (type: string) => {
const providerType = providerTypes.find((pt) => pt.id === type);
return providerType?.default_base_url || '';
@@ -1048,6 +1073,22 @@ export default function ProvidersPage() {
>
<Pencil className='h-4 w-4' />
</Button>
<Button
variant='ghost'
size='icon'
className='text-destructive hover:text-destructive h-8 w-8'
onClick={() =>
handleDeleteModel(
provider.id,
model.id
)
}
disabled={
deleteModelMutation.isPending
}
>
<Trash2 className='h-4 w-4' />
</Button>
</div>
</div>
))}