Skip to content

Commit 6d4f747

Browse files
committed
output-meta
1 parent d5cca8f commit 6d4f747

File tree

3 files changed

+137
-3
lines changed

3 files changed

+137
-3
lines changed

src/inferencesh/models/__init__.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@
1212
stream_generate,
1313
timing_context,
1414
)
15+
from .output_meta import (
16+
MetaItem,
17+
MetaItemType,
18+
TextMeta,
19+
ImageMeta,
20+
VideoMeta,
21+
VideoResolution,
22+
AudioMeta,
23+
OutputMeta,
24+
)
1525

1626
__all__ = [
1727
"BaseApp",
@@ -26,4 +36,13 @@
2636
"build_messages",
2737
"stream_generate",
2838
"timing_context",
39+
# OutputMeta types
40+
"MetaItem",
41+
"MetaItemType",
42+
"TextMeta",
43+
"ImageMeta",
44+
"VideoMeta",
45+
"VideoResolution",
46+
"AudioMeta",
47+
"OutputMeta",
2948
]

src/inferencesh/models/base.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from typing import Any, Dict, List, Optional
2-
from pydantic import BaseModel, ConfigDict
2+
from pydantic import BaseModel, ConfigDict, Field
33
import inspect
44
import ast
55
import textwrap
66
from collections import OrderedDict
77
from inferencesh.models.file import File
8-
from pydantic import Field
8+
from inferencesh.models.output_meta import OutputMeta
99

1010
class Metadata(BaseModel):
1111
app_id: Optional[str] = None
@@ -88,7 +88,10 @@ class BaseAppInput(OrderedSchemaModel):
8888

8989

9090
class BaseAppOutput(OrderedSchemaModel):
91-
pass
91+
output_meta: Optional[OutputMeta] = Field(
92+
default=None,
93+
description="Structured metadata about inputs/outputs for pricing calculation"
94+
)
9295

9396

9497
class BaseApp(BaseModel):
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
"""Output metadata types for pricing and usage tracking."""
2+
3+
from typing import Any, List, Optional
4+
from enum import Enum
5+
from pydantic import BaseModel, Field
6+
7+
8+
class MetaItemType(str, Enum):
9+
"""Type discriminator for MetaItem."""
10+
TEXT = "text"
11+
IMAGE = "image"
12+
VIDEO = "video"
13+
AUDIO = "audio"
14+
15+
16+
class VideoResolution(str, Enum):
17+
"""Standard video resolution presets."""
18+
RES_480P = "480p"
19+
RES_720P = "720p"
20+
RES_1080P = "1080p"
21+
RES_1440P = "1440p"
22+
RES_4K = "4k"
23+
24+
25+
class MetaItem(BaseModel):
26+
"""Base class for input/output metadata items."""
27+
type: str # "text", "image", "video", "audio"
28+
extra: Optional[dict[str, Any]] = Field(
29+
default=None,
30+
description="App-specific key-value pairs for custom pricing factors"
31+
)
32+
33+
34+
class TextMeta(MetaItem):
35+
"""Metadata for text inputs/outputs (e.g., LLM tokens)."""
36+
type: str = MetaItemType.TEXT.value
37+
tokens: int = Field(
38+
default=0,
39+
description="Token count - in inputs[] = input tokens, in outputs[] = output tokens"
40+
)
41+
42+
43+
class ImageMeta(MetaItem):
44+
"""Metadata for image inputs/outputs."""
45+
type: str = MetaItemType.IMAGE.value
46+
width: int = Field(default=0, description="Image width in pixels")
47+
height: int = Field(default=0, description="Image height in pixels")
48+
resolution_mp: float = Field(
49+
default=0,
50+
description="Resolution in megapixels (width * height / 1_000_000)"
51+
)
52+
steps: int = Field(default=0, description="Number of diffusion steps")
53+
count: int = Field(default=1, description="Number of images")
54+
55+
56+
class VideoMeta(MetaItem):
57+
"""Metadata for video inputs/outputs."""
58+
type: str = MetaItemType.VIDEO.value
59+
width: int = Field(default=0, description="Video width in pixels")
60+
height: int = Field(default=0, description="Video height in pixels")
61+
resolution_mp: float = Field(
62+
default=0,
63+
description="Resolution in megapixels per frame"
64+
)
65+
resolution: Optional[VideoResolution] = Field(
66+
default=None,
67+
description="Standard resolution preset (480p, 720p, 1080p, 1440p, 4k)"
68+
)
69+
seconds: float = Field(default=0, description="Duration in seconds")
70+
fps: int = Field(default=0, description="Frames per second")
71+
72+
73+
class AudioMeta(MetaItem):
74+
"""Metadata for audio inputs/outputs."""
75+
type: str = MetaItemType.AUDIO.value
76+
seconds: float = Field(default=0, description="Duration in seconds")
77+
sample_rate: int = Field(default=0, description="Sample rate in Hz")
78+
79+
80+
class OutputMeta(BaseModel):
81+
"""
82+
Structured metadata about task inputs and outputs for pricing calculation.
83+
84+
Apps include this in their output to report what was consumed (inputs)
85+
and what was produced (outputs). The backend uses this with CEL expressions
86+
to calculate app-level pricing.
87+
88+
Example usage in an LLM app:
89+
output_meta = OutputMeta(
90+
inputs=[TextMeta(tokens=150)],
91+
outputs=[TextMeta(tokens=500)]
92+
)
93+
94+
Example usage in a video generation app:
95+
output_meta = OutputMeta(
96+
outputs=[VideoMeta(
97+
resolution=VideoResolution.RES_1080P,
98+
resolution_mp=2.07,
99+
seconds=10.5,
100+
fps=30
101+
)]
102+
)
103+
"""
104+
inputs: List[MetaItem] = Field(
105+
default_factory=list,
106+
description="Metadata about consumed inputs"
107+
)
108+
outputs: List[MetaItem] = Field(
109+
default_factory=list,
110+
description="Metadata about produced outputs"
111+
)
112+

0 commit comments

Comments
 (0)