Skip to content

Add Gemini support and fix merge conflict in ai_service.py#48

Merged
cliff-de-tech merged 2 commits into
mainfrom
copilot/update-workflow-for-actions
Apr 8, 2026
Merged

Add Gemini support and fix merge conflict in ai_service.py#48
cliff-de-tech merged 2 commits into
mainfrom
copilot/update-workflow-for-actions

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 8, 2026

PR #27 introduced Gemini support but was committed with an unresolved merge conflict in _generate_with_gemini, causing a SyntaxError at startup. This integrates all Gemini changes cleanly with the conflict resolved.

Core changes

  • services/ai_service.pygoogle.generativeai import, GEMINI_API_KEY/GEMINI_MODEL constants, ModelProvider.GEMINI enum, Gemini in TIER_ALLOWED_PROVIDERS (PRO/ENTERPRISE), _generate_with_gemini() using genai.GenerativeModel (correct side of conflict), gemini_api_key param on generate_linkedin_post(), Gemini in provider dispatch table and get_available_providers()
  • backend/requirements.txt — Added google-generativeai==0.8.5
  • backend/routes/posts.pygemini_api_key wired through generate_preview, repurpose_url, and generate_batch; fallback provider list updated
  • backend/tests/test_bug_fixes.py — Added test_pro_user_can_use_gemini; updated provider set assertion from 4 → 5
  • Guides/SETUP_AI.md — Gemini row added to provider table and env var setup
  • Guides/SETUP_GEMINI.md — Deleted (was a verbatim duplicate of SETUP_AI.md)

Conflict resolution

The conflicted block had two implementations — genai.GenerativeModel (HEAD) vs raw requests.post with undefined url/payload locals. HEAD was correct; the code immediately following it calls model.generate_content().

# Resolved: keep genai.GenerativeModel approach
model = genai.GenerativeModel(
    model_name=GEMINI_MODEL,
    system_instruction=system_prompt,
    generation_config=genai.types.GenerationConfig(
        temperature=temperature,
        max_output_tokens=1000,
    ),
)
response = model.generate_content(user_prompt)

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>
@cliff-de-tech cliff-de-tech marked this pull request as ready for review April 8, 2026 11:05
Copilot AI review requested due to automatic review settings April 8, 2026 11:05
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_key through post-generation routes and expands provider metadata returned by the providers endpoint.
  • Updates docs/tests and adds the google-generativeai dependency; 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_PROVIDERS allows mistral for 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.

Comment thread services/ai_service.py
Comment on lines +1028 to +1033
try:
genai.configure(api_key=key)

model = genai.GenerativeModel(
model_name=GEMINI_MODEL,
system_instruction=system_prompt,
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment thread services/ai_service.py
"tier": "pro",
},
"gemini": {
"available": bool(GEMINI_API_KEY),
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
"available": bool(GEMINI_API_KEY),
"available": bool(GEMINI_API_KEY) and GEMINI_AVAILABLE,

Copilot uses AI. Check for mistakes.
Comment thread backend/routes/posts.py
Comment on lines 214 to +218
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')
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment thread backend/routes/posts.py
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')
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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.

Copilot uses AI. Check for mistakes.
Comment thread backend/routes/posts.py
Comment on lines 445 to +449
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')
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment thread services/ai_service.py
Comment on lines 1141 to 1145
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
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
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>
@cliff-de-tech cliff-de-tech merged commit a5a2f28 into main Apr 8, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants