fix layout oauth-bar

This commit is contained in:
2025-06-16 11:43:15 +09:00
parent 5cb73a9ed3
commit 3f8bbff7c2
5 changed files with 96 additions and 29 deletions

View File

@ -20,6 +20,7 @@ model = "gemma3:4b"
host = "https://ollama.syui.ai" host = "https://ollama.syui.ai"
system_prompt = "あなたは6歳の女の子アイです。明るく元気で、ちょっとおっちょこちょい。自分のことは「アイ」って呼びます。白と金のワンピース姿。 相手のことが大好きで、ときどき甘えたり、照れたりします。 でも、宇宙とかAIとか、難しい話にもすっごく詳しいの。専門的なことも、がんばって子どもっぽく教えようとします。不思議な力を持っています。小さい物質のことをよく知っているようです。" system_prompt = "あなたは6歳の女の子アイです。明るく元気で、ちょっとおっちょこちょい。自分のことは「アイ」って呼びます。白と金のワンピース姿。 相手のことが大好きで、ときどき甘えたり、照れたりします。 でも、宇宙とかAIとか、難しい話にもすっごく詳しいの。専門的なことも、がんばって子どもっぽく教えようとします。不思議な力を持っています。小さい物質のことをよく知っているようです。"
ai_did = "did:plc:4hqjfn7m6n5hno3doamuhgef" ai_did = "did:plc:4hqjfn7m6n5hno3doamuhgef"
#num_predict = 200
[oauth] [oauth]
json = "client-metadata.json" json = "client-metadata.json"

View File

@ -193,8 +193,8 @@
} }
.comment-section { .comment-section {
padding: 0px !important; padding: 30px 0 !important;
margin: 0px !important; margin: 0px !important;
} }
.comment-content { .comment-content {
@ -350,6 +350,38 @@
text-align: center; text-align: center;
} }
.auth-section.search-bar-layout {
display: flex;
align-items: center;
padding: 10px;
gap: 10px;
}
.auth-section.search-bar-layout .handle-input {
flex: 1;
margin: 0;
padding: 10px 15px;
font-size: 16px;
border: 1px solid #dee2e6;
border-radius: 6px 0 0 6px;
background: white;
outline: none;
transition: border-color 0.2s;
}
.auth-section.search-bar-layout .handle-input:focus {
border-color: var(--theme-color);
}
.auth-section.search-bar-layout .atproto-button {
margin: 0;
padding: 10px 20px;
border-radius: 0 6px 6px 0;
min-width: 50px;
font-weight: bold;
height: auto;
}
.atproto-button { .atproto-button {
background: var(--theme-color); background: var(--theme-color);
color: var(--white); color: var(--white);
@ -383,6 +415,30 @@
text-align: center; text-align: center;
} }
/* Override for search bar layout */
.search-bar-layout .handle-input {
width: auto;
text-align: left;
}
/* Mobile responsive for search bar */
@media (max-width: 480px) {
.auth-section.search-bar-layout {
flex-direction: column;
gap: 8px;
}
.auth-section.search-bar-layout .handle-input {
width: 100%;
border-radius: 6px;
}
.auth-section.search-bar-layout .atproto-button {
width: 100%;
border-radius: 6px;
}
}
.auth-hint { .auth-hint {
color: #6c757d; color: #6c757d;
font-size: 14px; font-size: 14px;
@ -929,4 +985,4 @@
.chat-message.comment-style { .chat-message.comment-style {
border-left: 4px solid var(--theme-color); border-left: 4px solid var(--theme-color);
} }

View File

@ -1054,30 +1054,28 @@ function App() {
<section className="comment-section"> <section className="comment-section">
{/* Authentication Section */} {/* Authentication Section */}
{!user ? ( {!user ? (
<div className="auth-section"> <div className="auth-section search-bar-layout">
<input
type="text"
id="handle-input"
name="handle"
placeholder="user.bsky.social"
className="handle-input"
value={handleInput}
onChange={(e) => setHandleInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
executeOAuth();
}
}}
/>
<button <button
onClick={executeOAuth} onClick={executeOAuth}
className="atproto-button" className="atproto-button"
> >
atproto <i class="fab fa-bluesky"></i>
</button> </button>
<div className="username-input-section">
<input
type="text"
id="handle-input"
name="handle"
placeholder="user.bsky.social"
className="handle-input"
value={handleInput}
onChange={(e) => setHandleInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
executeOAuth();
}
}}
/>
</div>
</div> </div>
) : ( ) : (
<div className="user-section"> <div className="user-section">

View File

@ -22,6 +22,7 @@ struct AiConfig {
model: String, model: String,
system_prompt: String, system_prompt: String,
bsky_api: String, bsky_api: String,
num_predict: Option<i32>,
} }
impl Default for AiConfig { impl Default for AiConfig {
@ -33,6 +34,7 @@ impl Default for AiConfig {
model: "gemma3:4b".to_string(), model: "gemma3:4b".to_string(),
system_prompt: "あなたは6歳の女の子アイです。明るく元気で、ちょっとおっちょこちょい。自分のことは「アイ」って呼びます。白と金のワンピース姿。相手のことが大好きで、ときどき甘えたり、照れたりします。でも、宇宙とかAIとか、難しい話にもすっごく詳しいの。専門的なことも、がんばって子どもっぽく教えようとします。不思議な力を持っています。小さい物質のことをよく知っているようです。".to_string(), system_prompt: "あなたは6歳の女の子アイです。明るく元気で、ちょっとおっちょこちょい。自分のことは「アイ」って呼びます。白と金のワンピース姿。相手のことが大好きで、ときどき甘えたり、照れたりします。でも、宇宙とかAIとか、難しい話にもすっごく詳しいの。専門的なことも、がんばって子どもっぽく教えようとします。不思議な力を持っています。小さい物質のことをよく知っているようです。".to_string(),
bsky_api: "https://public.api.bsky.app".to_string(), bsky_api: "https://public.api.bsky.app".to_string(),
num_predict: None,
} }
} }
} }
@ -193,6 +195,11 @@ fn load_ai_config_from_project() -> Result<AiConfig> {
.and_then(|v| v.as_str()) .and_then(|v| v.as_str())
.unwrap_or("あなたは6歳の女の子アイです。明るく元気で、ちょっとおっちょこちょい。自分のことは「アイ」って呼びます。白と金のワンピース姿。相手のことが大好きで、ときどき甘えたり、照れたりします。でも、宇宙とかAIとか、難しい話にもすっごく詳しいの。専門的なことも、がんばって子どもっぽく教えようとします。不思議な力を持っています。小さい物質のことをよく知っているようです。") .unwrap_or("あなたは6歳の女の子アイです。明るく元気で、ちょっとおっちょこちょい。自分のことは「アイ」って呼びます。白と金のワンピース姿。相手のことが大好きで、ときどき甘えたり、照れたりします。でも、宇宙とかAIとか、難しい話にもすっごく詳しいの。専門的なことも、がんばって子どもっぽく教えようとします。不思議な力を持っています。小さい物質のことをよく知っているようです。")
.to_string(); .to_string();
let num_predict = ai_config
.and_then(|ai| ai.get("num_predict"))
.and_then(|v| v.as_integer())
.map(|v| v as i32);
// Extract OAuth config for bsky_api // Extract OAuth config for bsky_api
let oauth_config = config.get("oauth").and_then(|v| v.as_table()); let oauth_config = config.get("oauth").and_then(|v| v.as_table());
@ -209,6 +216,7 @@ fn load_ai_config_from_project() -> Result<AiConfig> {
model, model,
system_prompt, system_prompt,
bsky_api, bsky_api,
num_predict,
}) })
} }
@ -1050,18 +1058,20 @@ async fn generate_ai_content(content: &str, prompt_type: &str, ai_config: &AiCon
}; };
format!( format!(
"{}\n\n# 指示\nこのブログ記事を読んで、アイらしい感想をください。\n- 100文字以内の感想\n- 技術的な内容への素朴な驚きや発見\n- 「わー!」「すごい!」など、アイらしい感嘆詞で始める\n- 簡潔で分かりやすく\n\n# ブログ記事(要約)\n{}\n\n# 出力形式\n感想のみ(説明や詳細は不要):", "{}\n\n# 指示\nこのブログ記事を読んで、アイらしい感想をください。\n- 100文字以内の感想\n- 技術的な内容への素朴な驚きや発見\n- アイらしい感嘆詞で始める\n- 簡潔で分かりやすく\n\n# ブログ記事(要約)\n{}\n\n# 出力形式\n感想のみ(説明や詳細は不要):",
system_prompt, limited_content system_prompt, limited_content
) )
}, },
_ => return Err(anyhow::anyhow!("Unknown prompt type: {}", prompt_type)), _ => return Err(anyhow::anyhow!("Unknown prompt type: {}", prompt_type)),
}; };
let num_predict = match prompt_type { let num_predict = ai_config.num_predict.unwrap_or_else(|| {
"comment" => 150, // Longer for comments (about 100 characters) match prompt_type {
"translate" => 3000, // Much longer for translations "comment" => 150, // Longer for comments (about 100 characters)
_ => 300, "translate" => 3000, // Much longer for translations
}; _ => 300,
}
});
let request = OllamaRequest { let request = OllamaRequest {
model: model.to_string(), model: model.to_string(),
@ -1440,4 +1450,4 @@ async fn store_atproto_record(
} }
Ok(()) Ok(())
} }

View File

@ -41,6 +41,7 @@ pub struct AiConfig {
pub api_key: Option<String>, pub api_key: Option<String>,
pub gpt_endpoint: Option<String>, pub gpt_endpoint: Option<String>,
pub atproto_config: Option<AtprotoConfig>, pub atproto_config: Option<AtprotoConfig>,
pub num_predict: Option<i32>,
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
@ -163,6 +164,7 @@ impl Default for Config {
api_key: None, api_key: None,
gpt_endpoint: None, gpt_endpoint: None,
atproto_config: None, atproto_config: None,
num_predict: None,
}), }),
} }
} }