Skip to content

Commit 5f7371d

Browse files
committed
fix(functions): restore language translation, and token/s display
1 parent 6d11f7a commit 5f7371d

File tree

1 file changed

+65
-25
lines changed

1 file changed

+65
-25
lines changed

resources/functions/openwebui_monitor.py

+65-25
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
"""
99

1010
import logging
11+
import time
1112
from typing import Dict, Optional
12-
1313
from httpx import AsyncClient
1414
from pydantic import BaseModel, Field
1515
import json
@@ -18,6 +18,27 @@
1818
logger = logging.getLogger(__name__)
1919
logger.setLevel(logging.INFO)
2020

21+
TRANSLATIONS = {
22+
"en": {
23+
"request_failed": "Request failed: {error_msg}",
24+
"insufficient_balance": "Insufficient balance: Current balance `{balance:.4f}`",
25+
"cost": "Cost: ${cost:.4f}",
26+
"balance": "Balance: ${balance:.4f}",
27+
"tokens": "Tokens: {input}+{output}",
28+
"time_spent": "Time: {time:.2f}s",
29+
"tokens_per_sec": "{tokens_per_sec:.2f} T/s",
30+
},
31+
"zh": {
32+
"request_failed": "请求失败: {error_msg}",
33+
"insufficient_balance": "余额不足: 当前余额 `{balance:.4f}`",
34+
"cost": "费用: ¥{cost:.4f}",
35+
"balance": "余额: ¥{balance:.4f}",
36+
"tokens": "Token: {input}+{output}",
37+
"time_spent": "耗时: {time:.2f}s",
38+
"tokens_per_sec": "{tokens_per_sec:.2f} T/s",
39+
},
40+
}
41+
2142

2243
class CustomException(Exception):
2344
pass
@@ -28,27 +49,41 @@ class Valves(BaseModel):
2849
api_endpoint: str = Field(default="", description="openwebui-monitor's base url")
2950
api_key: str = Field(default="", description="openwebui-monitor's api key")
3051
priority: int = Field(default=5, description="filter priority")
52+
language: str = Field(default="zh", description="language (en/zh)")
53+
show_time_spent: bool = Field(default=True, description="show time spent")
54+
show_tokens_per_sec: bool = Field(default=True, description="show tokens per second")
55+
show_cost: bool = Field(default=True, description="show cost")
56+
show_balance: bool = Field(default=True, description="show balance")
57+
show_tokens: bool = Field(default=True, description="show tokens")
3158

3259
def __init__(self):
3360
self.type = "filter"
61+
self.name = "OpenWebUI Monitor"
3462
self.valves = self.Valves()
3563
self.outage_map: Dict[str, bool] = {}
36-
64+
self.start_time: Optional[float] = None
65+
66+
def get_text(self, key: str, **kwargs) -> str:
67+
lang = self.valves.language if self.valves.language in TRANSLATIONS else "en"
68+
text = TRANSLATIONS[lang].get(key, TRANSLATIONS["en"][key])
69+
return text.format(**kwargs) if kwargs else text
70+
3771
async def request(self, client: AsyncClient, url: str, headers: dict, json_data: dict):
3872
json_data = json.loads(json.dumps(json_data, default=lambda o: o.dict() if hasattr(o, "dict") else str(o)))
3973

4074
response = await client.post(url=url, headers=headers, json=json_data)
4175
response.raise_for_status()
4276
response_data = response.json()
4377
if not response_data.get("success"):
44-
logger.error("[usage_monitor] req monitor failed: %s", response_data)
45-
raise CustomException("calculate usage failed, please contact administrator")
78+
logger.error(self.get_text("request_failed", error_msg=response_data))
79+
raise CustomException(self.get_text("request_failed", error_msg=response_data))
4680
return response_data
4781

4882
async def inlet(self, body: dict, __metadata__: Optional[dict] = None, __user__: Optional[dict] = None) -> dict:
4983
__user__ = __user__ or {}
5084
__metadata__ = __metadata__ or {}
51-
user_id = __user__["id"]
85+
self.start_time = time.time()
86+
user_id = __user__.get("id", "default")
5287

5388
client = AsyncClient()
5489

@@ -61,13 +96,12 @@ async def inlet(self, body: dict, __metadata__: Optional[dict] = None, __user__:
6196
)
6297
self.outage_map[user_id] = response_data.get("balance", 0) <= 0
6398
if self.outage_map[user_id]:
64-
logger.info("[usage_monitor] no balance: %s", user_id)
65-
raise CustomException("no balance, please contact administrator")
66-
99+
logger.info(self.get_text("insufficient_balance", balance=response_data.get("balance", 0)))
100+
raise CustomException(self.get_text("insufficient_balance", balance=response_data.get("balance", 0)))
67101
return body
68102

69103
except Exception as err:
70-
logger.exception("[usage_monitor] error calculating usage: %s", err)
104+
logger.exception(self.get_text("request_failed", error_msg=err))
71105
if isinstance(err, CustomException):
72106
raise err
73107
raise Exception(f"error calculating usage, {err}") from err
@@ -80,13 +114,13 @@ async def outlet(
80114
body: dict,
81115
__metadata__: Optional[dict] = None,
82116
__user__: Optional[dict] = None,
83-
__event_emitter__: callable = None,
117+
__event_emitter__: Optional[callable] = None,
84118
) -> dict:
85119
__user__ = __user__ or {}
86120
__metadata__ = __metadata__ or {}
87-
user_id = __user__["id"]
121+
user_id = __user__.get("id", "default")
88122

89-
if self.outage_map[user_id]:
123+
if self.outage_map.get(user_id, False):
90124
return body
91125

92126
client = AsyncClient()
@@ -99,23 +133,29 @@ async def outlet(
99133
json_data={"user": __user__, "body": body},
100134
)
101135

102-
# pylint: disable=C0209
103-
stats = " | ".join(
104-
[
105-
f"Tokens: {response_data['inputTokens']} + {response_data['outputTokens']}",
106-
"Cost: %.4f" % response_data["totalCost"],
107-
"Balance: %.4f" % response_data["newBalance"],
108-
]
109-
)
110-
111-
await __event_emitter__({"type": "status", "data": {"description": stats, "done": True}})
136+
stats_list = []
137+
if self.valves.show_tokens:
138+
stats_list.append(self.get_text("tokens", input=response_data["inputTokens"], output=response_data["outputTokens"]))
139+
if self.valves.show_cost:
140+
stats_list.append(self.get_text("cost", cost=response_data["totalCost"]))
141+
if self.valves.show_balance:
142+
stats_list.append(self.get_text("balance", balance=response_data["newBalance"]))
143+
if self.start_time and self.valves.show_time_spent:
144+
elapsed = time.time() - self.start_time
145+
stats_list.append(self.get_text("time_spent", time=elapsed))
146+
if self.valves.show_tokens_per_sec:
147+
tokens_per_sec = (response_data["outputTokens"] / elapsed if elapsed > 0 else 0)
148+
stats_list.append(self.get_text("tokens_per_sec", tokens_per_sec=tokens_per_sec))
149+
150+
stats = " | ".join(stats_list)
151+
if __event_emitter__:
152+
await __event_emitter__({"type": "status", "data": {"description": stats, "done": True}})
112153

113154
logger.info("usage_monitor: %s %s", user_id, stats)
114155
return body
115156

116157
except Exception as err:
117-
logger.exception("[usage_monitor] error calculating usage: %s", err)
118-
raise Exception(f"error calculating usage, {err}") from err
119-
158+
logger.exception(self.get_text("request_failed", error_msg=err))
159+
raise Exception(self.get_text("request_failed", error_msg=err))
120160
finally:
121161
await client.aclose()

0 commit comments

Comments
 (0)