update Gemini API : use thinking levels
This commit is contained in:
1 parent
7bc588e9a1
commit
ec6ac9580b
9 files changed
+161
-21
No files matched your search
@@ -20,6 +20,8 @@ from copienator import configuration as config
|
||||
from copienator.commands import grouping
|
||||
from copienator.answer_origins import save_origins
|
||||
from copienator import prompting
|
||||
from copienator.gemini_config import thinking_config
|
||||
from copienator import configuration as settings
|
||||
from copienator.feedback_boxes import valid_feedback_box
|
||||
from copienator.latex_json import repair_latex_json
|
||||
from copienator import (
|
||||
@@ -279,6 +281,9 @@ def call_gemini_with_retries(model_id, contents, config,
|
||||
# Switch to fallback immediately if quota was exhausted by another thread
|
||||
if model_id == MODEL_ID_pro and pro_quota_exhausted and fallback_model_id:
|
||||
model_id = fallback_model_id
|
||||
config = config.model_copy(update={"thinking_config": thinking_config(
|
||||
settings.THINKING_LEVEL_FLASH
|
||||
)})
|
||||
|
||||
try:
|
||||
full_response_text = ""
|
||||
@@ -312,6 +317,9 @@ def call_gemini_with_retries(model_id, contents, config,
|
||||
if is_quota_error and model_id == MODEL_ID_pro and fallback_model_id:
|
||||
tprint(f"\tGemini Pro quota hit ({e}). \n\n\tFalling back to Flash permanently...")
|
||||
model_id = fallback_model_id
|
||||
config = config.model_copy(update={"thinking_config": thinking_config(
|
||||
settings.THINKING_LEVEL_FLASH
|
||||
)})
|
||||
pro_quota_exhausted = True
|
||||
continue # Retry immediately with Flash
|
||||
|
||||
@@ -506,7 +514,11 @@ def process_single_task(task_tuple, precomputed_response=None):
|
||||
flash_count += 1
|
||||
|
||||
try:
|
||||
contents, config = prompting.generate_request(INPUT_DIR, file_path, label)
|
||||
contents, config = prompting.generate_request(
|
||||
INPUT_DIR, file_path, label,
|
||||
thinking_level=(settings.THINKING_LEVEL_FLASH if use_flash
|
||||
else settings.THINKING_LEVEL_PRO),
|
||||
)
|
||||
model_to_use = MODEL_ID_flash if use_flash else MODEL_ID_pro
|
||||
|
||||
if precomputed_response:
|
||||
@@ -891,13 +903,10 @@ def run_configured(args: argparse.Namespace) -> ExitCode:
|
||||
],
|
||||
}
|
||||
],
|
||||
"generation_config": {
|
||||
"temperature": 1.0,
|
||||
"topP": 0.95,
|
||||
"maxOutputTokens": 65535,
|
||||
"responseMimeType": "application/json",
|
||||
"responseSchema": prompting.UNROLLED_SCHEMA,
|
||||
},
|
||||
"generation_config": prompting.batch_generation_config(
|
||||
settings.THINKING_LEVEL_FLASH if use_flash
|
||||
else settings.THINKING_LEVEL_PRO
|
||||
),
|
||||
},
|
||||
}
|
||||
line = json.dumps(request)
|
||||
|
||||
@@ -26,6 +26,7 @@ from copienator import (
|
||||
workspace_from_args,
|
||||
)
|
||||
from copienator import configuration as config
|
||||
from copienator.gemini_config import thinking_config
|
||||
from copienator.filesystem import staged_files
|
||||
from copienator.latex_json import normalize_literal_newlines, repair_latex_json
|
||||
from copienator.platform import validate_windows_labels
|
||||
@@ -249,7 +250,7 @@ def _request_rubrics(client, group_context_text: str):
|
||||
config=types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
system_instruction="Rédige tous les barèmes et consignes de notation en français. Conserve les clés JSON, les labels et les formules mathématiques.",
|
||||
temperature=0.2,
|
||||
thinking_config=thinking_config(config.THINKING_LEVEL_LITE),
|
||||
response_mime_type="application/json",
|
||||
response_json_schema=GroupRubrics.model_json_schema(),
|
||||
),
|
||||
@@ -370,7 +371,7 @@ def refine_existing(workspace: EvaluationWorkspace, mode: str, *, api_client=Non
|
||||
))])],
|
||||
config=types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
temperature=0.1, response_mime_type="application/json",
|
||||
thinking_config=thinking_config(config.THINKING_LEVEL_LITE), response_mime_type="application/json",
|
||||
response_json_schema=LabelGroups.model_json_schema(),
|
||||
),
|
||||
)
|
||||
@@ -488,7 +489,7 @@ def process_exam(
|
||||
|
||||
config_1 = types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
temperature=0.1,
|
||||
thinking_config=thinking_config(config.THINKING_LEVEL_LITE),
|
||||
response_mime_type="application/json",
|
||||
response_json_schema=ExamQuestions.model_json_schema(),
|
||||
)
|
||||
@@ -505,7 +506,7 @@ def process_exam(
|
||||
|
||||
config_2 = types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
temperature=0.1,
|
||||
thinking_config=thinking_config(config.THINKING_LEVEL_LITE),
|
||||
response_mime_type="application/json",
|
||||
response_json_schema=ExamSolutions.model_json_schema(),
|
||||
)
|
||||
@@ -540,7 +541,7 @@ def process_exam(
|
||||
|
||||
config_3 = types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
temperature=0.1,
|
||||
thinking_config=thinking_config(config.THINKING_LEVEL_LITE),
|
||||
response_mime_type="application/json",
|
||||
response_json_schema=ExamContext.model_json_schema(),
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@ from google.genai import types
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from copienator import configuration as config
|
||||
from copienator.gemini_config import thinking_config
|
||||
from copienator import (
|
||||
CliError,
|
||||
EvaluationWorkspace,
|
||||
@@ -277,8 +278,7 @@ def generate_request(
|
||||
retry_options=types.HttpRetryOptions(attempts=1),
|
||||
),
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
temperature=1.0,
|
||||
top_p=0.95,
|
||||
thinking_config=thinking_config(config.THINKING_LEVEL_FOR_LABEL),
|
||||
seed=seed,
|
||||
max_output_tokens=65535,
|
||||
response_mime_type= "application/json",
|
||||
|
||||
@@ -32,6 +32,10 @@ else:
|
||||
_configuration = _load_user_config(CONFIG_PATH)
|
||||
|
||||
# Keep new optional settings compatible with older personal configuration files.
|
||||
THINKING_LEVEL_LITE = "low"
|
||||
THINKING_LEVEL_FOR_LABEL = "medium"
|
||||
THINKING_LEVEL_FLASH = "medium"
|
||||
THINKING_LEVEL_PRO = "high"
|
||||
ALWAYS_CROP = False
|
||||
SHOW_PERSONAL_STEPS = False
|
||||
RETURN_JPEG_ENABLED = True
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
from google.genai import types
|
||||
|
||||
|
||||
def thinking_config(level: str | None) -> types.ThinkingConfig | None:
|
||||
"""Use a supported reasoning level, or omit it for the model default."""
|
||||
if level is None:
|
||||
return None
|
||||
if level not in {"minimal", "low", "medium", "high"}:
|
||||
raise ValueError(
|
||||
f"Invalid Gemini thinking level {level!r}; "
|
||||
'expected "minimal", "low", "medium", "high", or None'
|
||||
)
|
||||
return types.ThinkingConfig(thinking_level=level)
|
||||
+19
-6
@@ -1,6 +1,8 @@
|
||||
from pathlib import Path
|
||||
import io
|
||||
from . import utils
|
||||
from . import configuration as settings
|
||||
from .gemini_config import thinking_config
|
||||
|
||||
PERSPECTIVE_GUIDANCE = (
|
||||
"Ce barème est indicatif, si une réponse est entièrement correcte mais utilise "
|
||||
@@ -173,8 +175,20 @@ UNROLLED_SCHEMA = {
|
||||
|
||||
from google.genai import types
|
||||
|
||||
def batch_generation_config(thinking_level):
|
||||
"""Build the REST generation config for a grading batch request."""
|
||||
config = {
|
||||
"maxOutputTokens": 65535,
|
||||
"responseMimeType": "application/json",
|
||||
"responseSchema": UNROLLED_SCHEMA,
|
||||
}
|
||||
thinking = thinking_config(thinking_level)
|
||||
if thinking is not None:
|
||||
config["thinkingConfig"] = thinking.model_dump(mode="json", by_alias=True, exclude_none=True)
|
||||
return config
|
||||
|
||||
# The root model for parsing is be: List[EvaluationEntry]
|
||||
def generate_request(input_dir, file, full_label):
|
||||
def generate_request(input_dir, file, full_label, *, thinking_level=settings.THINKING_LEVEL_PRO):
|
||||
"""Generates request for Gemini."""
|
||||
prompt = make_prompt(input_dir, full_label)
|
||||
image_path = Path(file)
|
||||
@@ -194,8 +208,7 @@ def generate_request(input_dir, file, full_label):
|
||||
|
||||
generate_content_config = types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
temperature=1.0,
|
||||
top_p=0.95,
|
||||
thinking_config=thinking_config(thinking_level),
|
||||
seed=0,
|
||||
max_output_tokens=65535,
|
||||
response_mime_type= "application/json",
|
||||
@@ -272,7 +285,7 @@ Commentaires d'origine :
|
||||
|
||||
config = types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
temperature=1.0,
|
||||
thinking_config=thinking_config(settings.THINKING_LEVEL_FLASH),
|
||||
response_mime_type="application/json",
|
||||
response_json_schema=TypeAdapter(List[FeedbackItem]).json_schema()
|
||||
)
|
||||
@@ -303,7 +316,7 @@ Voici les labels possibles. Ta réponse doit être l'un d'entre eux :
|
||||
types.Part.from_text(text=prompt)])]
|
||||
config = types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
temperature=1.0,
|
||||
thinking_config=thinking_config(settings.THINKING_LEVEL_FLASH),
|
||||
)
|
||||
return contents, config
|
||||
|
||||
@@ -334,7 +347,7 @@ d'entre eux :
|
||||
])]
|
||||
config = types.GenerateContentConfig(
|
||||
automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
|
||||
temperature=1.0,
|
||||
thinking_config=thinking_config(settings.THINKING_LEVEL_FLASH),
|
||||
response_mime_type="application/json",
|
||||
)
|
||||
return contents, config
|
||||
Reference in new issue
Block a user