{"id":24113717,"url":"https://github.com/rihoneailabs/llmcall","last_synced_at":"2026-04-11T06:11:33.817Z","repository":{"id":270705345,"uuid":"910048739","full_name":"rihoneailabs/llmcall","owner":"rihoneailabs","description":"A lite abstraction layer for structured LLM calls","archived":false,"fork":false,"pushed_at":"2025-01-02T14:32:18.000Z","size":225,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-13T03:34:13.742Z","etag":null,"topics":["ai","large-language-models","litellm","openai","structured-outputs"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rihoneailabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-30T11:15:54.000Z","updated_at":"2025-03-23T12:20:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"1d51aaa0-1ec4-4f85-a43d-211f04c90d40","html_url":"https://github.com/rihoneailabs/llmcall","commit_stats":null,"previous_names":["rihoneailabs/llmcall"],"tags_count":3,"template":true,"template_full_name":null,"purl":"pkg:github/rihoneailabs/llmcall","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rihoneailabs%2Fllmcall","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rihoneailabs%2Fllmcall/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rihoneailabs%2Fllmcall/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rihoneailabs%2Fllmcall/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rihoneailabs","download_url":"https://codeload.github.com/rihoneailabs/llmcall/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rihoneailabs%2Fllmcall/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31670617,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"online","status_checked_at":"2026-04-11T02:00:05.776Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","large-language-models","litellm","openai","structured-outputs"],"created_at":"2025-01-11T04:39:18.465Z","updated_at":"2026-04-11T06:11:33.809Z","avatar_url":"https://github.com/rihoneailabs.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LLMCall\n\nA lite abstraction layer for LLM calls.\n\n## Motivation\n\nAs AI becomes more prevalent in software development, there's a growing need for simple and intuitive APIs for \\\ninteracting with AI for quick text generation, decision making, and more. This is especially important now that we \\\nhave structured outputs, which allow us to seamlessly integrate AI into our application flow.\n\n`llmcall` provides a minimal intelligence interface for common LLM operations without unnecessary complexity.\n\n## Installation\n\n```bash\npip install llmcall\n```\n\n## Quick Start\n\n```bash\n# 1. Install\npip install llmcall\n\n# 2. Set your API key (copy .env.example to .env and fill in your key)\ncp .env.example .env\n```\n\n```python\n# 3. Use it\nfrom llmcall import generate\n\nresponse = generate(\"What is the capital of France?\")\nprint(response)  # Paris\n```\n\n## Configuration\n\nCopy `.env.example` to `.env` and set your values:\n\n```bash\n# Required\nLLMCALL_API_KEY=sk-...\n\n# Optional (defaults shown)\nLLMCALL_MODEL=openai/gpt-4.1\nLLMCALL_BASE_URL=          # for Ollama, Azure, LM Studio, etc.\nLLMCALL_DEBUG=false\n```\n\nOr set environment variables directly:\n\n```bash\nexport LLMCALL_API_KEY=sk-...\n```\n\n\u003e Uses [LiteLLM](https://docs.litellm.ai/docs/providers) under the hood — any supported provider works. We recommend OpenAI models for structured outputs.\n\n### Using local models (Ollama)\n\n```bash\nLLMCALL_MODEL=ollama/llama3.2\nLLMCALL_BASE_URL=http://localhost:11434\nLLMCALL_API_KEY=ollama\n```\n\n## Example Usage\n\n### Generation\n\n```python\nfrom llmcall import generate, generate_decision\nfrom pydantic import BaseModel\n\n# i. Basic generation\nresponse = generate(\"Write a story about a fictional holiday to the sun.\")\n\n# ii. Structured generation\nclass ResponseSchema(BaseModel):\n    story: str\n    tags: list[str]\n\nresponse: ResponseSchema = generate(\n    \"Create a rare story about the history of civilisation.\",\n    output_schema=ResponseSchema,\n)\n\n# iii. Streaming — get tokens as they arrive\nfor chunk in generate(\"Tell me a joke.\", stream=True):\n    print(chunk, end=\"\", flush=True)\n\n# iv. Decision making\ndecision = generate_decision(\n    \"Which is bigger?\",\n    options=[\"apple\", \"berry\", \"pumpkin\"],\n)\nprint(decision.selection)  # pumpkin\nprint(decision.reason)     # Pumpkins are significantly larger than...\n```\n\n### Async generation\n\n```python\nimport asyncio\nfrom llmcall import agenerate, agenerate_decision, aextract\n\n# Async generate\nresponse = await agenerate(\"Write a story about a fictional holiday to the sun.\")\n\n# Async streaming\nasync for chunk in await agenerate(\"Tell me a joke.\", stream=True):\n    print(chunk, end=\"\", flush=True)\n\n# Async decision\ndecision = await agenerate_decision(\"Which is bigger?\", options=[\"apple\", \"berry\", \"pumpkin\"])\n\n# Async extract\nresult = await aextract(text=my_text, output_schema=MySchema)\n\n# Run concurrently\nstory, decision = await asyncio.gather(\n    agenerate(\"Write a story.\"),\n    agenerate_decision(\"Which language?\", options=[\"Python\", \"Go\", \"Rust\"]),\n)\n```\n\n### Extraction\n\n```python\nfrom llmcall import extract, extract_pdf, extract_image\nfrom pydantic import BaseModel\n\nclass EmailSchema(BaseModel):\n    email_subject: str\n    email_body: str\n    email_topic: str\n    email_sentiment: str\n\n# i. Extract from plain text\ntext = \"\"\"To whom it may concern, Request for Admission at Harvard University ...\"\"\"\nresult: EmailSchema = extract(text=text, output_schema=EmailSchema)\n\n# ii. Extract from a PDF — URL, local path, or raw bytes all work\nclass InvoiceSchema(BaseModel):\n    vendor: str\n    total: float\n    line_items: list[str]\n\nresult: InvoiceSchema = extract_pdf(\n    source=\"https://example.com/invoice.pdf\",\n    output_schema=InvoiceSchema,\n)\n# local file\nresult: InvoiceSchema = extract_pdf(source=\"/path/to/invoice.pdf\", output_schema=InvoiceSchema)\n# raw bytes\nwith open(\"invoice.pdf\", \"rb\") as f:\n    result: InvoiceSchema = extract_pdf(source=f.read(), output_schema=InvoiceSchema)\n\n# iii. Extract from an image — URL, local path, or raw bytes all work\nclass ReceiptSchema(BaseModel):\n    store: str\n    total: float\n    items: list[str]\n\nresult: ReceiptSchema = extract_image(\n    source=\"https://example.com/receipt.jpg\",\n    output_schema=ReceiptSchema,\n)\n# local PNG (MIME type auto-detected from extension)\nresult: ReceiptSchema = extract_image(source=\"/path/to/receipt.png\", output_schema=ReceiptSchema)\n# raw bytes with explicit MIME type\nwith open(\"receipt.webp\", \"rb\") as f:\n    result: ReceiptSchema = extract_image(source=f.read(), output_schema=ReceiptSchema, media_type=\"image/webp\")\n```\n\n\u003e **Model requirements:** PDF extraction requires a model with document-understanding support\n\u003e (e.g. `anthropic/claude-sonnet-4-6`, `openai/gpt-4.1`, `google/gemini-3-flash-preview`).\n\u003e Image extraction requires a vision-capable model. An informative `ValueError` is raised if\n\u003e the configured model does not support the required capability.\n\n### Async multimodal extraction\n\n```python\nfrom llmcall import aextract_pdf, aextract_image\nimport asyncio\n\ninvoice, receipt = await asyncio.gather(\n    aextract_pdf(\"https://example.com/invoice.pdf\", InvoiceSchema),\n    aextract_image(\"https://example.com/receipt.jpg\", ReceiptSchema),\n)\n```\n\n## Roadmap\n\n- [x] Simple API for generating unstructured text\n- [x] Structured output generation using `Pydantic`\n- [x] Decision making\n- [x] Custom model selection (via `LiteLLM` - See [documentation](https://docs.litellm.ai/docs/providers))\n- [x] Custom base URL for OpenAI-compatible endpoints (Ollama, Azure, LM Studio)\n- [x] Structured text extraction\n- [x] Structured extraction from PDF (URL, local path, or bytes)\n- [x] Structured extraction from Images (URL, local path, or bytes)\n- [ ] Structured text extraction from Websites\n- [x] Async support (`agenerate`, `aextract`, `aextract_pdf`, `aextract_image`, `agenerate_decision`)\n- [x] Streaming support (`generate(..., stream=True)`, `agenerate(..., stream=True)`)\n\n## Documentation\n\nPlease refer to our comprehensive [documentation](./docs/index.md) to learn more about this tool.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frihoneailabs%2Fllmcall","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frihoneailabs%2Fllmcall","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frihoneailabs%2Fllmcall/lists"}