又是被佬友感动的一天

如题,佬友 @yangtb2024
真的是太热心了
从今天早上到现在,一直耐心和小白解答问题

包括serv00部署的new-api如何调用gemini最新模型
image
image

还有serv00部署的new-api不支持长文本的问题,也解决了
这个佬友花了好长时间不厌其烦解答,无敌了
image

image
image

23 个赞

发一面赛博锦旗 :nerd_face:

5 个赞

@yangtb2024 感谢佬友!

@前后注意空格,不然@不到

3 个赞

良好的论坛风气 :smirk:

1 个赞

tieba_013学会了

2 个赞

可以说是配享太庙啊 从早上到现在 哭了tieba_087

2 个赞

感谢佬友tieba_034,佬友才是真的好啊tieba_037

8 个赞

你学会了,可以教会更多的佬友

例如我赛博文盲

可以的应该? tieba_087

1 个赞

这种友好互助、无私奉献的氛围真的太棒了,在当今这个浮躁的互联网时代,站内的这种氛围犹如冬夜里的暖阳

再次感谢佬不厌其烦解答tieba_036

不支持长文本啥意思?看图中貌似你是全站开启了Under Attack(不建议),然后WAF设置了跳过规则,其实你需要跳过的路径还很多
image

就是用serv00部署的new-api,域名我的是托管在cloudflare上面的,但是默认情况下(指你没做任何waf操作),你输入长文本(token数量比如3500以上4000以上),他就会返回错误
如图
image
短文本token数少的,就正常回复
image

例如长文本代码,500多行的

// Configuration
const CACHE_DURATION_MINUTES = 50;//对话缓存时间 min
const CHECK_PERIOD_MINUTES = 240; //繁忙复位时间 min
const RETENTION_PERIOD_MINUTES = 240;
const BASE_URL = 'https://claude.asia';
const AUTH_ENDPOINT = '/manage-api/auth/oauth_token';
const CACHE_KEY = 'login_urls_cache';

// Convert minutes to milliseconds
const CACHE_DURATION_MS = CACHE_DURATION_MINUTES * 60 * 1000;
const CHECK_PERIOD_MS = CHECK_PERIOD_MINUTES * 60 * 1000;
const RETENTION_PERIOD_MS = RETENTION_PERIOD_MINUTES * 60 * 1000;

// Status constants
const STATUS = {
    BUSY: { color: 'busy', status: '繁忙' },
    FREE: { color: 'free', status: '空闲' }
};

//放SESSION_KEYS的地方,带引号,一行一个
const SESSION_KEYS = [
  // [email protected]
  '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',

  // [email protected] (新加坡三网)
  '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',

  // [email protected] (日本ijj)
  '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',

  // 共享的 keys
  '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',
  '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',
  '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'
];

async function getLoginUrl(sessionKey) {
    try {
        const response = await fetch(`${BASE_URL}${AUTH_ENDPOINT}`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                session_key: sessionKey,
                unique_name: Date.now().toString()
            }),
        });

        const data = await response.json();
        if (data.login_url) {
            return data.login_url.startsWith('http') 
                ? data.login_url 
                : `${BASE_URL}${data.login_url}`;
        }
    } catch (error) {
        console.error("Login URL Error:", error);
    }
    return '#';
}

async function getAccountStatus(accountNumber, env) {
    const key = `clicks_${accountNumber}`;
    const currentTime = Date.now();

    try {
        const clicks = await env.CLAUDE_KV.get(key, 'json') || [];
        const recentClicks = clicks.filter(time => (currentTime - time) < CHECK_PERIOD_MS);
      
        return recentClicks.length >= 1 ? STATUS.BUSY : STATUS.FREE;
    } catch (error) {
        console.error("Status Error:", error);
        return STATUS.FREE;
    }
}

async function updateClickTime(accountNumber, env) {
    const key = `clicks_${accountNumber}`;
    const currentTime = Date.now();

    try {
        const clicks = await env.CLAUDE_KV.get(key, 'json') || [];
        const recentClicks = clicks.filter(time => (currentTime - time) < RETENTION_PERIOD_MS);
        recentClicks.push(currentTime);
        await env.CLAUDE_KV.put(key, JSON.stringify(recentClicks));
    } catch (error) {
        console.error("Update Click Error:", error);
    }
}

async function generateHTML(loginUrls, accountStatuses) {
    return `<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>远大港湾</title>
    <style>
        body, html {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
            margin: 0;
            padding: 0;
            min-height: 100vh;
            background: linear-gradient(135deg, #ffffff, #f0f0f0);
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 0;
        }
        h1, h2 {
            color: #2c3e50;
            margin: 0;
        }
        .accounts {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
            gap: 15px;
            margin: 30px 0;
        }
        .account {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            min-height: 80px;
            text-decoration: none;
            padding: 12px 8px;
            border-radius: 12px;
            font-size: 0.95rem;
            transition: all 0.3s ease;
            border: 1px solid rgba(0,0,0,0.1);
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }
        .account.free {
            background-color: #81c784;
            color: #1b5e20;
        }
        .account.busy {
            background-color: #ef9a9a;
            color: #c62828;
        }
        .account:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }
        .account span {
            margin-top: 5px;
            font-size: 0.85rem;
            opacity: 0.9;
        }
        footer {
            margin-top: 40px;
            padding-top: 20px;
            border-top: 1px solid #eee;
            text-align: center;
            color: #666;
        }
        @media (max-width: 768px) {
            .accounts {
                grid-template-columns: repeat(3, 1fr);
                gap: 10px;
            }
            .account {
                min-height: 70px;
                padding: 10px 5px;
            }
        }
    </style>
    <script>
        function updateStatus(accountNumber, event) {
            event.preventDefault();
            const link = event.currentTarget;
            const url = link.href;
          
            fetch('?clicked=' + accountNumber)
                .then(() => {
                    window.open(url, '_blank');
                    setTimeout(() => location.reload(), 500);
                })
                .catch(console.error);
        }
    </script>
</head>
<body>
    <div class="container">
        <header>
            <img src="https://share.claude.asia/img/logo.png" height="30" alt="logo">
        </header>

        <main>
            <h2 style="text-align:center;">免费账号</h2>
            <div class="accounts">
                ${loginUrls.map((url, i) => `
                    <a href="${url}" 
                       class="account ${accountStatuses[i].color}" 
                       onclick="updateStatus(${i + 1}, event)">
                        账号${i + 1}
                        <span>(${accountStatuses[i].status})</span>
                    </a>
                `).join('')}
            </div>
        </main>

        <footer>
            <div class="copyright">©  Claude.asia</div>
        </footer>
    </div>
</body>
</html>`;
}

export default {
    async fetch(request, env) {
        const url = new URL(request.url);
      
        // Handle click updates
        if (url.searchParams.has('clicked')) {
            const clickedAccount = parseInt(url.searchParams.get('clicked'));
            if (clickedAccount > 0 && clickedAccount <= SESSION_KEYS.length) {
                await updateClickTime(clickedAccount, env);
            }
            return new Response('OK');
        }

        // Get login URLs from cache or API
        const cacheKey = 'login_urls_cache';
        let loginUrls;
      
        try {
            const cachedData = await env.CLAUDE_KV.get(cacheKey, 'json');
            if (cachedData && (Date.now() - cachedData.timestamp) < (CACHE_DURATION * 1000)) {
                loginUrls = cachedData.urls;
            } else {
                // Dynamically generate login URLs based on SESSION_KEYS length
                loginUrls = await Promise.all(SESSION_KEYS.map(key => getLoginUrl(key)));
                await env.CLAUDE_KV.put(cacheKey, JSON.stringify({
                    timestamp: Date.now(),
                    urls: loginUrls
                }));
            }
        } catch (error) {
            console.error("Cache Error:", error);
            loginUrls = await Promise.all(SESSION_KEYS.map(key => getLoginUrl(key)));
        }

        // Get account statuses dynamically based on SESSION_KEYS length
        const accountStatuses = await Promise.all(
            SESSION_KEYS.map((_, i) => getAccountStatus(i + 1, env))
        );

        // Generate and return HTML
        const html = await generateHTML(loginUrls, accountStatuses);
        return new Response(html, {
            headers: {
                'Content-Type': 'text/html;charset=UTF-8'
            }
        });
    }
};
// Configuration
const CACHE_DURATION_MINUTES = 50;//对话缓存时间 min
const CHECK_PERIOD_MINUTES = 240; //繁忙复位时间 min
const RETENTION_PERIOD_MINUTES = 240;
const BASE_URL = 'https://claude.asia';
const AUTH_ENDPOINT = '/manage-api/auth/oauth_token';
const CACHE_KEY = 'login_urls_cache';

// Convert minutes to milliseconds
const CACHE_DURATION_MS = CACHE_DURATION_MINUTES * 60 * 1000;
const CHECK_PERIOD_MS = CHECK_PERIOD_MINUTES * 60 * 1000;
const RETENTION_PERIOD_MS = RETENTION_PERIOD_MINUTES * 60 * 1000;

// Status constants
const STATUS = {
    BUSY: { color: 'busy', status: '繁忙' },
    FREE: { color: 'free', status: '空闲' }
};

//放SESSION_KEYS的地方,带引号,一行一个
const SESSION_KEYS = [
  // [email protected]
  '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',

  // [email protected] (新加坡三网)
  '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',

  // [email protected] (日本ijj)
  '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',

  // 共享的 keys
  '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',
  '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',
  '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'
];

async function getLoginUrl(sessionKey) {
    try {
        const response = await fetch(`${BASE_URL}${AUTH_ENDPOINT}`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                session_key: sessionKey,
                unique_name: Date.now().toString()
            }),
        });

        const data = await response.json();
        if (data.login_url) {
            return data.login_url.startsWith('http') 
                ? data.login_url 
                : `${BASE_URL}${data.login_url}`;
        }
    } catch (error) {
        console.error("Login URL Error:", error);
    }
    return '#';
}

async function getAccountStatus(accountNumber, env) {
    const key = `clicks_${accountNumber}`;
    const currentTime = Date.now();

    try {
        const clicks = await env.CLAUDE_KV.get(key, 'json') || [];
        const recentClicks = clicks.filter(time => (currentTime - time) < CHECK_PERIOD_MS);
      
        return recentClicks.length >= 1 ? STATUS.BUSY : STATUS.FREE;
    } catch (error) {
        console.error("Status Error:", error);
        return STATUS.FREE;
    }
}

async function updateClickTime(accountNumber, env) {
    const key = `clicks_${accountNumber}`;
    const currentTime = Date.now();

    try {
        const clicks = await env.CLAUDE_KV.get(key, 'json') || [];
        const recentClicks = clicks.filter(time => (currentTime - time) < RETENTION_PERIOD_MS);
        recentClicks.push(currentTime);
        await env.CLAUDE_KV.put(key, JSON.stringify(recentClicks));
    } catch (error) {
        console.error("Update Click Error:", error);
    }
}

async function generateHTML(loginUrls, accountStatuses) {
    return `<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>远大港湾</title>
    <style>
        body, html {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
            margin: 0;
            padding: 0;
            min-height: 100vh;
            background: linear-gradient(135deg, #ffffff, #f0f0f0);
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 0;
        }
        h1, h2 {
            color: #2c3e50;
            margin: 0;
        }
        .accounts {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
            gap: 15px;
            margin: 30px 0;
        }
        .account {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            min-height: 80px;
            text-decoration: none;
            padding: 12px 8px;
            border-radius: 12px;
            font-size: 0.95rem;
            transition: all 0.3s ease;
            border: 1px solid rgba(0,0,0,0.1);
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }
        .account.free {
            background-color: #81c784;
            color: #1b5e20;
        }
        .account.busy {
            background-color: #ef9a9a;
            color: #c62828;
        }
        .account:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }
        .account span {
            margin-top: 5px;
            font-size: 0.85rem;
            opacity: 0.9;
        }
        footer {
            margin-top: 40px;
            padding-top: 20px;
            border-top: 1px solid #eee;
            text-align: center;
            color: #666;
        }
        @media (max-width: 768px) {
            .accounts {
                grid-template-columns: repeat(3, 1fr);
                gap: 10px;
            }
            .account {
                min-height: 70px;
                padding: 10px 5px;
            }
        }
    </style>
    <script>
        function updateStatus(accountNumber, event) {
            event.preventDefault();
            const link = event.currentTarget;
            const url = link.href;
          
            fetch('?clicked=' + accountNumber)
                .then(() => {
                    window.open(url, '_blank');
                    setTimeout(() => location.reload(), 500);
                })
                .catch(console.error);
        }
    </script>
</head>
<body>
    <div class="container">
        <header>
            <img src="https://share.claude.asia/img/logo.png" height="30" alt="logo">
        </header>

        <main>
            <h2 style="text-align:center;">免费账号</h2>
            <div class="accounts">
                ${loginUrls.map((url, i) => `
                    <a href="${url}" 
                       class="account ${accountStatuses[i].color}" 
                       onclick="updateStatus(${i + 1}, event)">
                        账号${i + 1}
                        <span>(${accountStatuses[i].status})</span>
                    </a>
                `).join('')}
            </div>
        </main>

        <footer>
            <div class="copyright">©  Claude.asia</div>
        </footer>
    </div>
</body>
</html>`;
}

export default {
    async fetch(request, env) {
        const url = new URL(request.url);
      
        // Handle click updates
        if (url.searchParams.has('clicked')) {
            const clickedAccount = parseInt(url.searchParams.get('clicked'));
            if (clickedAccount > 0 && clickedAccount <= SESSION_KEYS.length) {
                await updateClickTime(clickedAccount, env);
            }
            return new Response('OK');
        }

        // Get login URLs from cache or API
        const cacheKey = 'login_urls_cache';
        let loginUrls;
      
        try {
            const cachedData = await env.CLAUDE_KV.get(cacheKey, 'json');
            if (cachedData && (Date.now() - cachedData.timestamp) < (CACHE_DURATION * 1000)) {
                loginUrls = cachedData.urls;
            } else {
                // Dynamically generate login URLs based on SESSION_KEYS length
                loginUrls = await Promise.all(SESSION_KEYS.map(key => getLoginUrl(key)));
                await env.CLAUDE_KV.put(cacheKey, JSON.stringify({
                    timestamp: Date.now(),
                    urls: loginUrls
                }));
            }
        } catch (error) {
            console.error("Cache Error:", error);
            loginUrls = await Promise.all(SESSION_KEYS.map(key => getLoginUrl(key)));
        }

        // Get account statuses dynamically based on SESSION_KEYS length
        const accountStatuses = await Promise.all(
            SESSION_KEYS.map((_, i) => getAccountStatus(i + 1, env))
        );

        // Generate and return HTML
        const html = await generateHTML(loginUrls, accountStatuses);
        return new Response(html, {
            headers: {
                'Content-Type': 'text/html;charset=UTF-8'
            }
        });
    }
};

咳咳 under attack是啥,意思是我下面的这些有些不需要开启是吗?
具体是哪些不需要开启tieba_028
image

佬 你这个规则选的是啥,我看你可以添加好多路径
我是下面这个
image

等下,我试下serv00的看看有没你这问题

既然这么详细,建议整理成新人笔记,把爱传递下去

3 个赞

我试了下serv00的没有长文本问题啊,你后面改了什么设置?
Under Attack开了后全站都会质询,没有必要
image

如果开盾了规则这里这样写更好

image

我默认啥也没改啊
我部署了好几个佬友的new-api和one-api服务
如图所示,部署了6个,用了3个域名,都是长本文有问题
image

试了下没遇到你说的问题:tieba_033:

佬 你这个under attack在哪关的
image

我想问下下面这些应该没啥问题吧
image