aimd-api 0.9.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
aimd_api/__init__.py ADDED
@@ -0,0 +1,22 @@
1
+ """HTTP API package for aimd."""
2
+
3
+ from importlib import import_module
4
+
5
+ __all__ = [
6
+ "EngineCapabilityResponse",
7
+ "EnginesResponse",
8
+ "HealthResponse",
9
+ "ProcessRequest",
10
+ "ProcessResponse",
11
+ "app",
12
+ "create_app",
13
+ "main",
14
+ ]
15
+
16
+
17
+ def __getattr__(name: str):
18
+ if name in __all__:
19
+ app_module = import_module(".app", __name__)
20
+
21
+ return getattr(app_module, name)
22
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
aimd_api/app.py ADDED
@@ -0,0 +1,158 @@
1
+ """FastAPI service package for aimd."""
2
+
3
+ from importlib.metadata import version
4
+ import os
5
+
6
+ from fastapi import FastAPI, HTTPException
7
+ from logly import logger
8
+ from pydantic import BaseModel, Field
9
+
10
+ from aimd.application.bootstrap import build_container
11
+ from aimd.application.models import TaskType
12
+ from aimd.application.services.interface_payloads import (
13
+ build_process_input,
14
+ engine_capabilities_payload,
15
+ get_request_temp_dir,
16
+ process_result_payload,
17
+ )
18
+ from aimd.application.services.output_writer import persist_result_output_if_requested
19
+ from aimd.errors import AimdError
20
+
21
+
22
+ class HealthResponse(BaseModel):
23
+ status: str = "ok"
24
+
25
+
26
+ class EngineCapabilityResponse(BaseModel):
27
+ name: str
28
+ available: bool
29
+ reason: str | None = None
30
+ fix_hint: str | None = None
31
+ selected_by_auto: bool = False
32
+
33
+
34
+ class EnginesResponse(BaseModel):
35
+ auto_selected_engine: str | None = None
36
+ engines: list[EngineCapabilityResponse]
37
+
38
+
39
+ class ProcessRequest(BaseModel):
40
+ input_source: str = Field(
41
+ ..., description="Audio/video file path, video URL, or document file path."
42
+ )
43
+ output_file: str | None = Field(
44
+ default=None, description="Optional path to write resulting markdown output."
45
+ )
46
+ transcribe_engine: str = Field(
47
+ default="auto",
48
+ description="Transcription engine: auto, mlx, qwen.",
49
+ )
50
+ model: str | None = Field(
51
+ default=None,
52
+ description="Model for transcription. mlx defaults to mlx-community/Qwen3-ASR-1.7B-4bit "
53
+ "and also supports other documented mlx-audio STT model IDs. "
54
+ "qwen supports Qwen/Qwen3-ASR-1.7B (default) or Qwen/Qwen3-ASR-0.6B.",
55
+ )
56
+ language: str | None = Field(
57
+ default=None, description="Language code for transcription, e.g. zh, en, ja."
58
+ )
59
+ save_original: str | None = Field(
60
+ default=None,
61
+ description="Optional path to persist downloaded audio from URL processing.",
62
+ )
63
+ cookies: str | None = Field(
64
+ default=None,
65
+ description="Path to Netscape-format cookies file for URL extraction.",
66
+ )
67
+ cookies_from_browser: str | None = Field(
68
+ default=None,
69
+ description="Browser cookie source for URL extraction, e.g. chrome:default.",
70
+ )
71
+ raw_transcript: bool = Field(
72
+ default=False,
73
+ description="Preserve original subtitle formatting (SRT/VTT timestamps). "
74
+ "By default, subtitles are simplified to plain text.",
75
+ )
76
+
77
+
78
+ class ProcessResponse(BaseModel):
79
+ task_type: TaskType
80
+ title: str
81
+ chunk_list: list[str]
82
+ split_header_level: int | None = None
83
+ platform: str | None = None
84
+ output_file: str | None = None
85
+ output_dir: str | None = None
86
+
87
+
88
+ def create_app() -> FastAPI:
89
+ """Build FastAPI app instance."""
90
+ app = FastAPI(
91
+ title="aimd API",
92
+ description="Context preparation API for LLM workflows",
93
+ version=version("aimd-cli"),
94
+ )
95
+ container = build_container()
96
+
97
+ @app.get("/healthz", response_model=HealthResponse)
98
+ async def healthz() -> HealthResponse:
99
+ return HealthResponse()
100
+
101
+ @app.get("/v1/engines", response_model=EnginesResponse)
102
+ async def engines() -> EnginesResponse:
103
+ result = container.list_engines_use_case.execute()
104
+ return EnginesResponse(**engine_capabilities_payload(result))
105
+
106
+ @app.post("/v1/process", response_model=ProcessResponse)
107
+ async def process(request: ProcessRequest) -> ProcessResponse:
108
+ try:
109
+ temp_dir = get_request_temp_dir()
110
+
111
+ result = await container.process_input_use_case.execute(
112
+ build_process_input(
113
+ input_source=request.input_source,
114
+ transcribe_engine=request.transcribe_engine,
115
+ model=request.model,
116
+ language=request.language,
117
+ save_original=request.save_original,
118
+ cookies=request.cookies,
119
+ cookies_from_browser=request.cookies_from_browser,
120
+ temp_dir=temp_dir,
121
+ raw_transcript=request.raw_transcript,
122
+ )
123
+ )
124
+
125
+ persisted = persist_result_output_if_requested(result, request.output_file)
126
+ if persisted.ignored_output_file:
127
+ logger.warning(
128
+ "Ignoring output_file for book conversions; output is a directory."
129
+ )
130
+
131
+ return ProcessResponse(
132
+ **process_result_payload(
133
+ result,
134
+ output_file=persisted.output_file,
135
+ output_dir=persisted.output_dir,
136
+ )
137
+ )
138
+ except AimdError as exc:
139
+ raise HTTPException(status_code=exc.status_code, detail=str(exc)) from exc
140
+ except ValueError as exc:
141
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
142
+ except Exception as exc:
143
+ logger.error(f"API processing failed: {exc}")
144
+ raise HTTPException(status_code=500, detail=str(exc)) from exc
145
+
146
+ return app
147
+
148
+
149
+ app = create_app()
150
+
151
+
152
+ def main() -> None:
153
+ """Run FastAPI service via uvicorn."""
154
+ import uvicorn
155
+
156
+ host = os.getenv("AIMD_API_HOST", "127.0.0.1")
157
+ port = int(os.getenv("AIMD_API_PORT", "8000"))
158
+ uvicorn.run("aimd_api:app", host=host, port=port, reload=False)
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.3
2
+ Name: aimd-api
3
+ Version: 0.9.2
4
+ Summary: FastAPI service for aimd.
5
+ Author: Shu Li
6
+ Author-email: Shu Li <zetarylee@gmail.com>
7
+ Requires-Dist: aimd-cli
8
+ Requires-Dist: fastapi>=0.116.1
9
+ Requires-Dist: uvicorn>=0.35.0
10
+ Requires-Python: >=3.10, <3.13
@@ -0,0 +1,6 @@
1
+ aimd_api/__init__.py,sha256=YLH1Wgf_cKn7nOlQpiUbKptSnUXY2AZxxrKVcc3z41A,472
2
+ aimd_api/app.py,sha256=u1KeAOgFWfy4ecxwiF0BBiad9clDniRbeIsxsvFnHBY,5338
3
+ aimd_api-0.9.2.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
4
+ aimd_api-0.9.2.dist-info/entry_points.txt,sha256=sgB6NImUHyK7NwaqyFQmV_fUdxN05bQiroJC-HqwFJw,44
5
+ aimd_api-0.9.2.dist-info/METADATA,sha256=J99mmz97dmM2MphEcEaCPAgBPDVUOyPeHRnIt-pc2ss,263
6
+ aimd_api-0.9.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.8.24
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ aimd-api = aimd_api:main
3
+