Skip to content

Commit c26aad3

Browse files
committed
fix(cli): fix bugs about doc2anki list
1 parent 4cd3ac9 commit c26aad3

7 files changed

Lines changed: 127 additions & 27 deletions

File tree

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ default_model = "deepseek-chat"
113113

114114
配置完成后,通过 `doc2anki list` 列出当前配置文件中被 enable 的 api providers, `doc2anki list --all` 列出所有 providers
115115

116-
注:现在的 `doc2anki list` 还无法无法读 dotenv 文件中的 providers, 只能读到 `default_base_url``default_model`
117-
118116
## 使用
119117

120118
### 查看可用的模型提供商
@@ -145,6 +143,12 @@ doc2anki generate docs/ -p provider_name -o output.apkg
145143

146144
### 命令行选项
147145

146+
**全局选项:**
147+
148+
| 选项 | 说明 |
149+
|-----|------|
150+
| `-v, --version` | 显示版本号并退出 |
151+
148152
**基本选项:**
149153

150154
| 选项 | 默认值 | 说明 |

docs/cli-reference.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ uv run doc2anki --help
2626
```
2727
doc2anki [OPTIONS] COMMAND [ARGS]
2828
29+
Options:
30+
-v, --version 显示版本号并退出
31+
2932
Commands:
3033
list 列出可用的 AI 提供商
3134
validate 验证配置文件
@@ -34,6 +37,22 @@ Commands:
3437

3538
---
3639

40+
## 全局选项
41+
42+
| 选项 | 说明 |
43+
|-----|------|
44+
| `-v, --version` | 显示版本号并退出 |
45+
46+
### 示例
47+
48+
```sh
49+
# 显示版本号
50+
doc2anki --version
51+
doc2anki -v
52+
```
53+
54+
---
55+
3756
## doc2anki list
3857

3958
列出配置文件中的 AI 提供商。

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "doc2anki"
3-
version = "0.1.1"
3+
version = "0.1.2"
44
description = "Convert knowledge base documents to Anki flashcards"
55
readme = "README.md"
66
requires-python = ">=3.12"

src/doc2anki/cli.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""CLI interface for doc2anki."""
22

33
import os
4+
from importlib.metadata import version as get_version
45
from pathlib import Path
56
from typing import Optional
67

@@ -15,13 +16,37 @@
1516
fatal_exit,
1617
)
1718

19+
20+
def version_callback(value: bool) -> None:
21+
"""Print version and exit."""
22+
if value:
23+
pkg_version = get_version("doc2anki")
24+
print(f"doc2anki {pkg_version}")
25+
raise typer.Exit()
26+
27+
1828
app = typer.Typer(
1929
name="doc2anki",
2030
help="Convert knowledge base documents to Anki flashcards",
2131
no_args_is_help=True,
2232
)
2333
console = Console()
2434

35+
36+
@app.callback()
37+
def main(
38+
version: bool = typer.Option(
39+
False,
40+
"-v",
41+
"--version",
42+
help="Show version and exit",
43+
callback=version_callback,
44+
is_eager=True,
45+
),
46+
) -> None:
47+
"""doc2anki - Convert knowledge base documents to Anki flashcards."""
48+
pass
49+
2550
# Config file name
2651
CONFIG_FILENAME = "ai_providers.toml"
2752

src/doc2anki/config/loader.py

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,10 @@ def _resolve_env_auth(provider_name: str, config: dict[str, Any]) -> ProviderCon
9090
f"'{config['api_key']}' not set or empty"
9191
)
9292

93+
# base_url field contains the env var name to look up
9394
base_url = None
94-
if "base_url_env" in config:
95-
base_url = os.getenv(config["base_url_env"])
95+
if "base_url" in config:
96+
base_url = os.getenv(config["base_url"])
9697
if not base_url:
9798
base_url = config.get("default_base_url")
9899
if not base_url:
@@ -101,9 +102,10 @@ def _resolve_env_auth(provider_name: str, config: dict[str, Any]) -> ProviderCon
101102
f"(env var not set and no default)"
102103
)
103104

105+
# model field contains the env var name to look up
104106
model = None
105-
if "model_env" in config:
106-
model = os.getenv(config["model_env"])
107+
if "model" in config:
108+
model = os.getenv(config["model"])
107109
if not model:
108110
model = config.get("default_model")
109111
if not model:
@@ -142,9 +144,10 @@ def _resolve_dotenv_auth(provider_name: str, config: dict[str, Any]) -> Provider
142144
f"not found in {dotenv_path}"
143145
)
144146

147+
# base_url field contains the key name to look up in dotenv
145148
base_url = None
146-
if "base_url_key" in config:
147-
base_url = os.getenv(config["base_url_key"])
149+
if "base_url" in config:
150+
base_url = os.getenv(config["base_url"])
148151
if not base_url:
149152
base_url = config.get("default_base_url")
150153
if not base_url:
@@ -153,9 +156,10 @@ def _resolve_dotenv_auth(provider_name: str, config: dict[str, Any]) -> Provider
153156
f"(not in dotenv and no default)"
154157
)
155158

159+
# model field contains the key name to look up in dotenv
156160
model = None
157-
if "model_key" in config:
158-
model = os.getenv(config["model_key"])
161+
if "model" in config:
162+
model = os.getenv(config["model"])
159163
if not model:
160164
model = config.get("default_model")
161165
if not model:
@@ -201,6 +205,53 @@ def get_provider_config(config_path: Path, provider_name: str) -> ProviderConfig
201205
return resolve_provider_config(provider_name, provider_config)
202206

203207

208+
def _resolve_display_values_env(config: dict[str, Any]) -> tuple[str | None, str | None]:
209+
"""Resolve base_url and model for env auth type for display purposes."""
210+
base_url = None
211+
model = None
212+
213+
# base_url/model fields contain env var names
214+
if "base_url" in config:
215+
base_url = os.getenv(config["base_url"])
216+
if not base_url:
217+
base_url = config.get("default_base_url")
218+
219+
if "model" in config:
220+
model = os.getenv(config["model"])
221+
if not model:
222+
model = config.get("default_model")
223+
224+
return base_url, model
225+
226+
227+
def _resolve_display_values_dotenv(
228+
config: dict[str, Any],
229+
) -> tuple[str | None, str | None]:
230+
"""Resolve base_url and model for dotenv auth type for display purposes."""
231+
base_url = None
232+
model = None
233+
234+
# Try to load dotenv file if it exists
235+
if "dotenv_path" in config:
236+
dotenv_path = Path(config["dotenv_path"])
237+
if dotenv_path.exists():
238+
load_dotenv(dotenv_path, override=True)
239+
240+
# base_url/model fields contain key names in dotenv
241+
if "base_url" in config:
242+
base_url = os.getenv(config["base_url"])
243+
if "model" in config:
244+
model = os.getenv(config["model"])
245+
246+
# Fallback to defaults
247+
if not base_url:
248+
base_url = config.get("default_base_url")
249+
if not model:
250+
model = config.get("default_model")
251+
252+
return base_url, model
253+
254+
204255
def list_providers(config_path: Path, show_all: bool = False) -> list[ProviderInfo]:
205256
"""
206257
List all providers from configuration.
@@ -225,16 +276,17 @@ def list_providers(config_path: Path, show_all: bool = False) -> list[ProviderIn
225276

226277
auth_type = config.get("auth_type", "unknown")
227278

228-
# Try to get model info without resolving full config
279+
# Resolve actual model and base_url values
229280
model = None
230281
base_url = None
231282

232283
if auth_type == "direct":
233284
model = config.get("model")
234285
base_url = config.get("base_url")
235-
elif auth_type in ("env", "dotenv"):
236-
model = config.get("default_model")
237-
base_url = config.get("default_base_url")
286+
elif auth_type == "env":
287+
base_url, model = _resolve_display_values_env(config)
288+
elif auth_type == "dotenv":
289+
base_url, model = _resolve_display_values_dotenv(config)
238290

239291
providers.append(
240292
ProviderInfo(

src/doc2anki/config/models.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,24 @@ class EnvAuthConfig(BaseModel):
2727

2828
enable: bool = False
2929
auth_type: Literal["env"]
30-
base_url_env: Optional[str] = None
31-
model_env: Optional[str] = None
32-
api_key: str # Environment variable name containing the API key
33-
default_base_url: Optional[str] = None
34-
default_model: Optional[str] = None
30+
base_url: str # Environment variable name for base URL
31+
model: str # Environment variable name for model
32+
api_key: str # Environment variable name for API key
33+
default_base_url: Optional[str] = None # Fallback if env var not set
34+
default_model: Optional[str] = None # Fallback if env var not set
3535

3636

3737
class DotenvAuthConfig(BaseModel):
3838
"""Dotenv file authentication."""
3939

4040
enable: bool = False
4141
auth_type: Literal["dotenv"]
42-
dotenv_path: str
43-
base_url_key: Optional[str] = None
44-
model_key: Optional[str] = None
45-
api_key: str # Key name in the dotenv file containing the API key
46-
default_base_url: Optional[str] = None
47-
default_model: Optional[str] = None
42+
dotenv_path: str # Path to .env file
43+
base_url: str # Key name in .env file for base URL
44+
model: str # Key name in .env file for model
45+
api_key: str # Key name in .env file for API key
46+
default_base_url: Optional[str] = None # Fallback if key not in .env
47+
default_model: Optional[str] = None # Fallback if key not in .env
4848

4949

5050
class ProviderInfo(BaseModel):

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)