Skip to content

Commit c72480f

Browse files
psychedeliciousMary Hipp
authored andcommitted
fix: opencv dependency conflict (#8095)
* build: prevent `opencv-python` from being installed Fixes this error: `AttributeError: module 'cv2.ximgproc' has no attribute 'thinning'` `opencv-contrib-python` supersedes `opencv-python`, providing the same API + additional features. The two packages should not be installed at the same time to avoid conflicts and/or errors. The `invisible-watermark` package requires `opencv-python`, but we require the contrib variant. This change updates `pyproject.toml` to prevent `opencv-python` from ever being installed using a `uv` features called dependency overrides. * feat(ui): data viewer supports disabling wrap * feat(api): list _all_ pkgs in app deps endpoint * chore(ui): typegen * feat(ui): update about modal to display new full deps list * chore: uv lock
1 parent 3704573 commit c72480f

File tree

8 files changed

+46
-129
lines changed

8 files changed

+46
-129
lines changed

invokeai/app/api/routers/app_info.py

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import typing
22
from enum import Enum
3-
from importlib.metadata import PackageNotFoundError, version
3+
from importlib.metadata import distributions
44
from pathlib import Path
5-
from platform import python_version
65
from typing import Optional
76

87
import torch
@@ -44,24 +43,6 @@ class AppVersion(BaseModel):
4443
highlights: Optional[list[str]] = Field(default=None, description="Highlights of release")
4544

4645

47-
class AppDependencyVersions(BaseModel):
48-
"""App depencency Versions Response"""
49-
50-
accelerate: str = Field(description="accelerate version")
51-
compel: str = Field(description="compel version")
52-
cuda: Optional[str] = Field(description="CUDA version")
53-
diffusers: str = Field(description="diffusers version")
54-
numpy: str = Field(description="Numpy version")
55-
opencv: str = Field(description="OpenCV version")
56-
onnx: str = Field(description="ONNX version")
57-
pillow: str = Field(description="Pillow (PIL) version")
58-
python: str = Field(description="Python version")
59-
torch: str = Field(description="PyTorch version")
60-
torchvision: str = Field(description="PyTorch Vision version")
61-
transformers: str = Field(description="transformers version")
62-
xformers: Optional[str] = Field(description="xformers version")
63-
64-
6546
class AppConfig(BaseModel):
6647
"""App Config Response"""
6748

@@ -76,27 +57,19 @@ async def get_version() -> AppVersion:
7657
return AppVersion(version=__version__)
7758

7859

79-
@app_router.get("/app_deps", operation_id="get_app_deps", status_code=200, response_model=AppDependencyVersions)
80-
async def get_app_deps() -> AppDependencyVersions:
60+
@app_router.get("/app_deps", operation_id="get_app_deps", status_code=200, response_model=dict[str, str])
61+
async def get_app_deps() -> dict[str, str]:
62+
deps: dict[str, str] = {dist.metadata["Name"]: dist.version for dist in distributions()}
8163
try:
82-
xformers = version("xformers")
83-
except PackageNotFoundError:
84-
xformers = None
85-
return AppDependencyVersions(
86-
accelerate=version("accelerate"),
87-
compel=version("compel"),
88-
cuda=torch.version.cuda,
89-
diffusers=version("diffusers"),
90-
numpy=version("numpy"),
91-
opencv=version("opencv-python"),
92-
onnx=version("onnx"),
93-
pillow=version("pillow"),
94-
python=python_version(),
95-
torch=torch.version.__version__,
96-
torchvision=version("torchvision"),
97-
transformers=version("transformers"),
98-
xformers=xformers,
99-
)
64+
cuda = torch.version.cuda or "N/A"
65+
except Exception:
66+
cuda = "N/A"
67+
68+
deps["CUDA"] = cuda
69+
70+
sorted_deps = dict(sorted(deps.items(), key=lambda item: item[0].lower()))
71+
72+
return sorted_deps
10073

10174

10275
@app_router.get("/config", operation_id="get_config", status_code=200, response_model=AppConfig)

invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type Props = {
1919
withDownload?: boolean;
2020
withCopy?: boolean;
2121
extraCopyActions?: { label: string; getData: (data: unknown) => unknown }[];
22+
wrapData?: boolean;
2223
} & FlexProps;
2324

2425
const overlayscrollbarsOptions = getOverlayScrollbarsParams({
@@ -29,7 +30,16 @@ const overlayscrollbarsOptions = getOverlayScrollbarsParams({
2930
const ChakraPre = chakra('pre');
3031

3132
const DataViewer = (props: Props) => {
32-
const { label, data, fileName, withDownload = true, withCopy = true, extraCopyActions, ...rest } = props;
33+
const {
34+
label,
35+
data,
36+
fileName,
37+
withDownload = true,
38+
withCopy = true,
39+
extraCopyActions,
40+
wrapData = true,
41+
...rest
42+
} = props;
3343
const dataString = useMemo(() => (isString(data) ? data : formatter.Serialize(data)) ?? '', [data]);
3444
const shift = useShiftModifier();
3545
const clipboard = useClipboard();
@@ -53,7 +63,7 @@ const DataViewer = (props: Props) => {
5363
<Flex bg="base.800" borderRadius="base" flexGrow={1} w="full" h="full" position="relative" {...rest}>
5464
<Box position="absolute" top={0} left={0} right={0} bottom={0} overflow="auto" p={2} fontSize="sm">
5565
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayscrollbarsOptions}>
56-
<ChakraPre whiteSpace="pre-wrap">{dataString}</ChakraPre>
66+
<ChakraPre whiteSpace={wrapData ? 'pre-wrap' : undefined}>{dataString}</ChakraPre>
5767
</OverlayScrollbarsComponent>
5868
</Box>
5969
<Flex position="absolute" top={0} insetInlineEnd={0} p={2}>

invokeai/frontend/web/src/features/system/components/AboutModal/AboutModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ const AboutModal = ({ children }: AboutModalProps) => {
5858
{cloneElement(children, {
5959
onClick: onOpen,
6060
})}
61-
<Modal isOpen={isOpen} onClose={onClose} isCentered size="2xl" useInert={false}>
61+
<Modal isOpen={isOpen} onClose={onClose} isCentered size="5xl" useInert={false}>
6262
<ModalOverlay />
6363
<ModalContent maxH="80vh" h="34rem">
6464
<ModalHeader>{t('accessibility.about')}</ModalHeader>
6565
<ModalCloseButton />
6666
<ModalBody display="flex" flexDir="column" gap={4}>
6767
<Grid templateColumns="repeat(2, 1fr)" h="full">
6868
<GridItem backgroundColor="base.750" borderRadius="base" p="4" h="full">
69-
<DataViewer label={t('common.systemInformation')} data={localData} />
69+
<DataViewer label={t('common.systemInformation')} data={localData} wrapData={false} />
7070
</GridItem>
7171
<GridItem>
7272
<Flex flexDir="column" gap={3} justifyContent="center" alignItems="center" h="full">

invokeai/frontend/web/src/services/api/endpoints/appInfo.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { $openAPISchemaUrl } from 'app/store/nanostores/openAPISchemaUrl';
22
import type { OpenAPIV3_1 } from 'openapi-types';
33
import type { paths } from 'services/api/schema';
4-
import type { AppConfig, AppDependencyVersions, AppVersion } from 'services/api/types';
4+
import type { AppConfig, AppVersion } from 'services/api/types';
55

66
import { api, buildV1Url } from '..';
77

@@ -22,7 +22,10 @@ export const appInfoApi = api.injectEndpoints({
2222
}),
2323
providesTags: ['FetchOnReconnect'],
2424
}),
25-
getAppDeps: build.query<AppDependencyVersions, void>({
25+
getAppDeps: build.query<
26+
paths['/api/v1/app/app_deps']['get']['responses']['200']['content']['application/json'],
27+
void
28+
>({
2629
query: () => ({
2730
url: buildAppInfoUrl('app_deps'),
2831
method: 'GET',

invokeai/frontend/web/src/services/api/schema.ts

Lines changed: 3 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,77 +1925,6 @@ export type components = {
19251925
*/
19261926
watermarking_methods: string[];
19271927
};
1928-
/**
1929-
* AppDependencyVersions
1930-
* @description App depencency Versions Response
1931-
*/
1932-
AppDependencyVersions: {
1933-
/**
1934-
* Accelerate
1935-
* @description accelerate version
1936-
*/
1937-
accelerate: string;
1938-
/**
1939-
* Compel
1940-
* @description compel version
1941-
*/
1942-
compel: string;
1943-
/**
1944-
* Cuda
1945-
* @description CUDA version
1946-
*/
1947-
cuda: string | null;
1948-
/**
1949-
* Diffusers
1950-
* @description diffusers version
1951-
*/
1952-
diffusers: string;
1953-
/**
1954-
* Numpy
1955-
* @description Numpy version
1956-
*/
1957-
numpy: string;
1958-
/**
1959-
* Opencv
1960-
* @description OpenCV version
1961-
*/
1962-
opencv: string;
1963-
/**
1964-
* Onnx
1965-
* @description ONNX version
1966-
*/
1967-
onnx: string;
1968-
/**
1969-
* Pillow
1970-
* @description Pillow (PIL) version
1971-
*/
1972-
pillow: string;
1973-
/**
1974-
* Python
1975-
* @description Python version
1976-
*/
1977-
python: string;
1978-
/**
1979-
* Torch
1980-
* @description PyTorch version
1981-
*/
1982-
torch: string;
1983-
/**
1984-
* Torchvision
1985-
* @description PyTorch Vision version
1986-
*/
1987-
torchvision: string;
1988-
/**
1989-
* Transformers
1990-
* @description transformers version
1991-
*/
1992-
transformers: string;
1993-
/**
1994-
* Xformers
1995-
* @description xformers version
1996-
*/
1997-
xformers: string | null;
1998-
};
19991928
/**
20001929
* AppVersion
20011930
* @description App Version Response
@@ -24226,7 +24155,9 @@ export interface operations {
2422624155
[name: string]: unknown;
2422724156
};
2422824157
content: {
24229-
"application/json": components["schemas"]["AppDependencyVersions"];
24158+
"application/json": {
24159+
[key: string]: string;
24160+
};
2423024161
};
2423124162
};
2423224163
};

invokeai/frontend/web/src/services/api/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ export type InvocationJSONSchemaExtra = S['UIConfigBase'];
3131
// App Info
3232
export type AppVersion = S['AppVersion'];
3333
export type AppConfig = S['AppConfig'];
34-
export type AppDependencyVersions = S['AppDependencyVersions'];
3534

3635
// Images
3736
export type ImageDTO = S['ImageDTO'];

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ dependencies = [
109109
"humanize==4.12.1",
110110
]
111111

112+
[tool.uv]
113+
# Prevent opencv-python from ever being chosen during dependency resolution.
114+
# This prevents conflicts with opencv-contrib-python, which Invoke requires.
115+
override-dependencies = ["opencv-python; sys_platform=='never'"]
116+
117+
112118
[project.scripts]
113119
"invokeai-web" = "invokeai.app.run_app:run_app"
114120

uv.lock

Lines changed: 5 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)