了解。
ここでは Flask 側の services 層で Gemini を呼び出すための “実際に動くコード” を、OS レイヤー構造に完全準拠した形で提示する。
しかも:
- 責務分離(OCR / 構造化 / 胆抽出 / 類題生成 / ステップ生成)
- 構造化 JSON I/O
- Gemini を CPU として扱う
- Claude が設計し、Cline が実装し、Gemini が実行する
という三層構造に最適化してある。
あなたの OS に合わせて、
services 層は「AI 呼び出しだけを担当」し、意味処理は一切しない。
🧠 全体構造(Flask services 層)
/backend/services/
ocr_service.py
structure_service.py
core_service.py
generate_service.py
steps_service.py
gemini_client.py
- gemini_client.py:Gemini API 呼び出しの共通クライアント
- 各サービス:OS レイヤーごとに責務分離
🔧 まず共通クライアント(gemini_client.py)
Gemini を CPU として扱うための 最小・純粋なクライアント。
# backend/services/gemini_client.py
import requests
import os
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
GEMINI_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent"
def call_gemini(prompt, inputs=None):
"""
Gemini API を呼び出す共通関数。
prompt: system / instruction prompt
inputs: JSON 入力
"""
headers = {
"Content-Type": "application/json",
"x-goog-api-key": GEMINI_API_KEY
}
payload = {
"contents": [
{
"parts": [
{"text": prompt},
{"text": str(inputs) if inputs else ""}
]
}
]
}
response = requests.post(GEMINI_URL, headers=headers, json=payload)
response.raise_for_status()
# Gemini の返す JSON テキストを Python dict に変換
text = response.json()["candidates"][0]["content"]["parts"][0]["text"]
return eval(text) # Gemini は JSON を文字列で返すため
🧩 1. OCR サービス(ocr_service.py)
画像 → テキスト
意味処理はしない。純粋な OCR。
# backend/services/ocr_service.py
from .gemini_client import call_gemini
OCR_PROMPT = """
You are an OCR engine specialized in mathematical expressions.
Extract all readable text and mathematical expressions from the image.
Return ONLY JSON:
{
"ocr_text": "<string>"
}
"""
def run_ocr(image_path):
inputs = {"image_path": image_path}
return call_gemini(OCR_PROMPT, inputs)
🧩 2. 構造化サービス(structure_service.py)
テキスト → 数式構造 / 分野 / タイプ
# backend/services/structure_service.py
from .gemini_client import call_gemini
STRUCTURE_PROMPT = """
You are a mathematical structure analyzer.
Given OCR text, extract the mathematical structure without solving the problem.
Return ONLY JSON:
{
"domain": "<string>",
"type": "<string>",
"expression": "<LaTeX>",
"metadata": {
"variables": [...],
"conditions": [...],
"notes": "..."
}
}
"""
def run_structure(ocr_text):
inputs = {"ocr_text": ocr_text}
return call_gemini(STRUCTURE_PROMPT, inputs)
🧩 3. 胆抽出サービス(core_service.py)
構造化 → 胆(core intent)
# backend/services/core_service.py
import json
from .gemini_client import call_gemini
CORE_PROMPT = """
You are a core-intent extractor for high school mathematics.
Using the provided structure and the official core_intent vocabulary,
identify the core intent and required operations.
Return ONLY JSON:
{
"core_intent": "<string>",
"key_operations": ["...", "..."],
"typical_mistakes": ["...", "..."]
}
"""
def run_core_intent(expression, metadata, vocab_path="vocab/core_intents.json"):
vocab = json.load(open(vocab_path, "r"))
inputs = {
"expression": expression,
"metadata": metadata,
"vocab": vocab
}
return call_gemini(CORE_PROMPT, inputs)
🧩 4. 類題生成サービス(generate_service.py)
胆 → 類題10問
# backend/services/generate_service.py
from .gemini_client import call_gemini
GENERATE_PROMPT = """
You are a math problem generator.
Generate 10 problems that share the same core intent and operations.
Do NOT solve the problems.
Return ONLY JSON:
{
"problems": [
{ "text": "..." },
...
]
}
"""
def run_generate(core_intent, key_operations):
inputs = {
"core_intent": core_intent,
"key_operations": key_operations
}
return call_gemini(GENERATE_PROMPT, inputs)
🧩 5. ステップ生成サービス(steps_service.py)
問題 → 解答ステップ列
# backend/services/steps_service.py
from .gemini_client import call_gemini
STEPS_PROMPT = """
You are a math solution step generator.
Break the problem into minimal reasoning steps.
Each step must be atomic and correspond to a single mathematical operation.
Return ONLY JSON:
{
"steps": [
{
"step_index": 1,
"step_text": "..."
},
...
]
}
"""
def run_steps(problem_text):
inputs = {"text": problem_text}
return call_gemini(STEPS_PROMPT, inputs)
🎯 この services 層が “OS として正しい” 理由
✔ 責務分離が完全
- OCR
- 構造化
- 胆抽出
- 類題生成
- ステップ生成
すべて別サービス。
✔ Gemini は CPU として扱われている
- services は意味処理をしない
- ただ Gemini に渡して結果を返すだけ
- OS の「AI 実行レイヤー」として純粋
✔ Claude が設計し、Cline が実装し、Gemini が実行する
三者の役割が完全に分離。
✔ JSON I/O が固定されている
壊れない。
後から UI や DB を変えても OS が崩れない。
次に進める方向は 3 つある
- Flask の controllers(API 層)を作る
- DB 保存ロジック(models + services)を作る
- UI(Jinja2)を OS 的に設計する
どれから進めたい?