Add Gemini support and fix merge conflict in ai_service.py#48
Conversation
Agent-Logs-Url: https://github.com/cliff-de-tech/Post-Bot/sessions/d06decff-0bd5-4581-a518-b1cb339d6f61 Co-authored-by: cliff-de-tech <137389025+cliff-de-tech@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR integrates Google Gemini as an additional AI generation provider and resolves a previously committed merge conflict in services/ai_service.py that caused a startup SyntaxError, restoring a clean import/runtime path for the AI service.
Changes:
- Adds Gemini as a PRO-tier model provider (SDK import, env vars/constants, provider routing, and availability reporting).
- Wires
gemini_api_keythrough post-generation routes and expands provider metadata returned by the providers endpoint. - Updates docs/tests and adds the
google-generativeaidependency; removes a duplicate Gemini setup guide.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| services/ai_service.py | Adds Gemini provider implementation, tier allowlist entry, routing map entry, and availability metadata. |
| backend/routes/posts.py | Passes gemini_api_key through generation endpoints and updates provider messaging/fallback provider list. |
| backend/requirements.txt | Adds google-generativeai==0.8.5. |
| backend/tests/test_bug_fixes.py | Adds tier-enforcement test for Gemini and updates provider set assertions. |
| Guides/SETUP_AI.md | Documents Gemini in the provider table and env var setup. |
| Guides/SETUP_GEMINI.md | Removes duplicate setup guide. |
| README.md | Updates top-level documentation references to include Gemini. |
Comments suppressed due to low confidence (1)
services/ai_service.py:13
- The module docstring says free users are "ALWAYS routed to Groq", but
TIER_ALLOWED_PROVIDERSallowsmistralfor the Free tier. Since this file is being edited, it would be good to align the docstring with the actual tier enforcement behavior to avoid misleading future changes/docs.
- Gemini (Pro tier) - Gemini 1.5 Flash
TIER ENFORCEMENT:
- Free users are ALWAYS routed to Groq, even if they request premium models
- Pro users can choose any provider
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| try: | ||
| genai.configure(api_key=key) | ||
|
|
||
| model = genai.GenerativeModel( | ||
| model_name=GEMINI_MODEL, | ||
| system_instruction=system_prompt, |
There was a problem hiding this comment.
genai.configure(api_key=key) sets global SDK state. Because generation is run in asyncio.to_thread, concurrent requests with different per-user Gemini keys can race and send prompts using the wrong user's API key (cross-tenant credential leak). Prefer a per-request/per-key client that does not mutate global config; if the SDK only supports global configuration, guard configure + request with a module-level lock and restore prior config to avoid leakage.
| "tier": "pro", | ||
| }, | ||
| "gemini": { | ||
| "available": bool(GEMINI_API_KEY), |
There was a problem hiding this comment.
get_available_providers() reports Gemini as available based only on GEMINI_API_KEY. If the google-generativeai package isn't installed (GEMINI_AVAILABLE is False), the API will still advertise Gemini as available even though all calls will fail. Consider incorporating GEMINI_AVAILABLE into the availability calculation (and optionally expose a separate "installed" flag).
| "available": bool(GEMINI_API_KEY), | |
| "available": bool(GEMINI_API_KEY) and GEMINI_AVAILABLE, |
| if settings: | ||
| groq_api_key = settings.get('groq_api_key') | ||
| openai_api_key = settings.get('openai_api_key') | ||
| anthropic_api_key = settings.get('anthropic_api_key') | ||
| gemini_api_key = settings.get('gemini_api_key') |
There was a problem hiding this comment.
get_user_settings (from services/user_settings.py) does not return a gemini_api_key field (it only returns preference/persona/subscription fields), so this will always pass None and per-user Gemini keys can't work. Either fetch Gemini credentials from the correct storage layer (if supported) or remove this wiring to avoid a false sense of support.
| groq_api_key = settings.get('groq_api_key') | ||
| openai_api_key = settings.get('openai_api_key') | ||
| anthropic_api_key = settings.get('anthropic_api_key') | ||
| gemini_api_key = settings.get('gemini_api_key') |
There was a problem hiding this comment.
Same issue as in generate_preview: settings from get_user_settings does not include gemini_api_key, so this assignment will always be None. If per-user AI keys are meant to be supported, this endpoint should retrieve them from the correct store; otherwise, omit these fields.
| gemini_api_key = settings.get('gemini_api_key') | |
| # `get_user_settings` does not provide a per-user Gemini key. | |
| # Leave `gemini_api_key` as None unless it is retrieved from the | |
| # correct credential store in a future change. |
| if settings: | ||
| groq_api_key = settings.get('groq_api_key') | ||
| openai_api_key = settings.get('openai_api_key') | ||
| anthropic_api_key = settings.get('anthropic_api_key') | ||
| gemini_api_key = settings.get('gemini_api_key') |
There was a problem hiding this comment.
Same issue as above: get_user_settings doesn't include gemini_api_key, so batch generation will never use a per-user Gemini key. Wire this to the actual credential storage (if applicable) or remove the unused plumbing.
| groq_api_key: Optional override for Groq API key | ||
| openai_api_key: Optional override for OpenAI API key | ||
| anthropic_api_key: Optional override for Anthropic API key | ||
| gemini_api_key: Optional override for Gemini API key | ||
| persona_context: Optional persona prompt string |
There was a problem hiding this comment.
Docstring/provider documentation is inconsistent with the implementation: the Args section now mentions gemini_api_key, but the earlier docstring text and model_provider description still imply only groq/openai/anthropic are supported. Please update the docstring to reflect the full set of routed providers (including mistral and gemini) and current tier behavior.
Resolved merge conflicts in: - README.md: Combined Mistral and Gemini in AI providers list - services/ai_service.py: Kept correct genai.GenerativeModel implementation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: cliff-de-tech <137389025+cliff-de-tech@users.noreply.github.com>
PR #27 introduced Gemini support but was committed with an unresolved merge conflict in
_generate_with_gemini, causing aSyntaxErrorat startup. This integrates all Gemini changes cleanly with the conflict resolved.Core changes
services/ai_service.py—google.generativeaiimport,GEMINI_API_KEY/GEMINI_MODELconstants,ModelProvider.GEMINIenum, Gemini inTIER_ALLOWED_PROVIDERS(PRO/ENTERPRISE),_generate_with_gemini()usinggenai.GenerativeModel(correct side of conflict),gemini_api_keyparam ongenerate_linkedin_post(), Gemini in provider dispatch table andget_available_providers()backend/requirements.txt— Addedgoogle-generativeai==0.8.5backend/routes/posts.py—gemini_api_keywired throughgenerate_preview,repurpose_url, andgenerate_batch; fallback provider list updatedbackend/tests/test_bug_fixes.py— Addedtest_pro_user_can_use_gemini; updated provider set assertion from 4 → 5Guides/SETUP_AI.md— Gemini row added to provider table and env var setupGuides/SETUP_GEMINI.md— Deleted (was a verbatim duplicate ofSETUP_AI.md)Conflict resolution
The conflicted block had two implementations —
genai.GenerativeModel(HEAD) vs rawrequests.postwith undefinedurl/payloadlocals. HEAD was correct; the code immediately following it callsmodel.generate_content().